-
11Step 11
Control Panels
Parts:
- MAX004 IP67 Hard Case – 350 x 230 x 86H mm MAX004S 2 of
- MAX001 IP67 Hard Case – 175 x 115 x 47H mm MAX001S 1 of
- Arduino Mega 2560
- Adafruit Feather 32u4 FONA
- Adafruit Audio FX Sound Board - WAV/OGG Trigger
- 20 x 4 LCD display
- Hackable Prototyping Board
There are 3 panel boxes in the NanoStillery™, the main panel is driven by an Arduino Mega and the secondary one houses an Adafruit Feather GPRS board for transmitting data to the interweb. The third box has a large 12 volt power supply and a bank of relays in it.
The main control panel receives information from the various sensors in the system - temperatures, pressure and alcohol vapour levels and controls various valves, pump and the boiler heater via the relays. It then communicates with the Adafruit Feather via the I2C bus which then sends the data to a database where it is accessed from this webpage: NanoStillery
The GPRS module could very well have been bolted into the main control panel, but, for one, I had run out of room and secondly, I wanted the module to be removable so that it could be used for other projects in the future. Getting the two 'machines' to communicate with each other effectively was quite challenging. It was ok if the numbers were just simple small integers, but as soon as more complex 'floats' were involved, some serious number crunching code had to be developed. This can be seen in the 'Code' step.
-
12Step 12
Electrical Schematics and Parts
Electrical parts:
- DS2 DS18B20 1-Wire Temperature Sensor Probe Cable
- DS3 DS18B20 1-Wire Temperature Sensor Probe Cable
- DS4 DS18B20 1-Wire Temperature Sensor Probe Cable
- DS5 DS18B20 1-Wire Temperature Sensor Probe Cable
- IC1 Voltage Regulator chip 78005; variant sink; voltage 5V; package to220-igo
- J1 Piezo Speaker LCD1 LCD screen type Character; pins 16 LED1 Red (633nm)
- LED color Red (633nm); leg yes; package 5 mm [THT]; part # GPRS CONNECTED
- LED2 Red (633nm) LED color Red (633nm); leg yes; package 5 mm [THT]; part # DATA RECIEVED
- Part1 Adafruit Feather 32u4 FONA variant variant 1; part # Adafruit #3027
- Part2 Arduino Mega 2560 (Rev3) type Arduino MEGA 2560 (Rev3)
- Q1 NPN-Transistor type NPN (EBC); package TO92 [THT]
- Q2 NPN-Transistor type NPN (EBC); package TO92 [THT]
- Q3 NPN-Transistor type NPN (EBC); package TO92 [THT]
- Q4 NPN-Transistor type NPN (EBC); package TO92 [THT]
- Q5 NPN-Transistor type NPN (EBC); package TO92 [THT]
- R1 Rotary Potentiometer (Small) type Rotary Shaft Potentiometer; size Rotary - 9mm; maximum resistance 100kΩ; track Linear; package THT
- R4 4.7kΩ Resistor tolerance ±5%; pin spacing 400 mil; bands 4; package THT; resistance 4.7kΩ
- R5 100Ω Resistor tolerance ±5%; pin spacing 400 mil; bands 4; package THT; resistance 100Ω
- R6 1kΩ Resistor tolerance ±5%; pin spacing 400 mil; bands 4; package THT; resistance 1kΩ
- R7 1kΩ Resistor tolerance ±5%; pin spacing 400 mil; bands 4; package THT; resistance 1kΩ
- R8 1kΩ Resistor tolerance ±5%; pin spacing 400 mil; bands 4; package THT; resistance 1kΩ
- R9 1kΩ Resistor tolerance ±5%; pin spacing 400 mil; bands 4; package THT; resistance 1kΩ
- R10 1kΩ Resistor tolerance ±5%; pin spacing 400 mil; bands 4; package THT; resistance 1kΩ
- R11 Rotary Potentiometer (Small) type Rotary Shaft Potentiometer; size Rotary - 9mm; maximum resistance 100kΩ; track Linear; package THT; part # HEATER
- R12 Rotary Potentiometer (Small) type Rotary Shaft Potentiometer; size Rotary - 9mm; maximum resistance 100kΩ; track Linear; package THT; part # PUMP TIMER
- R13 Rotary Potentiometer (Small) type Rotary Shaft Potentiometer; size Rotary - 9mm; maximum resistance 100kΩ; track Linear; package THT; part # END TEMPERATURE
- R14 10kΩ Resistor tolerance ±5%; package 2512 [SMD]; resistance 10kΩ
- R15 10kΩ Resistor tolerance ±5%; package 2512 [SMD]; resistance 10kΩ
- R16 1kΩ Resistor tolerance ±5%; package 2512 [SMD]; resistance 1kΩ
- R17 1kΩ Resistor tolerance ±5%; package 2512 [SMD]; resistance 1kΩ
- S1 SWITCH-MOMENTARY-2 variant 12mm; package tactile-pth-12mm
- S2 SWITCH-MOMENTARY-2 variant 12mm; package tactile-pth-12mm
- U1 RELAY-2 variant g5q; package relay-g5v; part # HYDROMETER DUMP
- U2 RELAY-2 variant g5q; package relay-g5v; part # PUMP LH
- U3 RELAY-2 variant g5q; package relay-g5v; part # PUMP RH
- U4 RELAY-2 variant g5q; package relay-g5v; part # HEATER
- U5 RELAY-2 variant g5q; package relay-g5v; part # PUMP
- U6 GAS_SENSOR package mq-3 VALVE1 Plastic Solenoid Valve part # HYDROMETER DUMP
- VALVE2 Plastic Solenoid Valve part # PUMP LH VALVE3 Plastic Solenoid Valve part # PUMP RH
- VCC1 Battery block 9V voltage 9V; part # 12V (NOT 9V)
- VCC2 4 x AAA Battery Mount voltage 4.8V
-
13Step 13
Pump and 3 Way Valves
Parts:
- Pevekoil 12V-3/2-way solenoid valve
- 12V DC 4L/min 100PSI Water Pump High Pressure Diaphragm For Boot RV Caravan UK
This system allows the same pump to be used for filling and emptying the boiler, depending on how the 3 way valves are set. The pump itself is a diaphragm type that is self priming so can be positioned anywhere in the frame.
The pump and valves are controlled via small 'sugar cube' 12v relays. Some of the relays or perhaps the solenoids, I'm not sure, interfered with the LCD screen for a while but this was cured by using large 470uF capacitors wired in parallel with the offending device. The capacitors must not be too large or else the solenoids would not open quick enough.
-
14Step 14
Arduino Mega Code
The code in the main control panel is fairly standard except for the part which sends data down the I2C bus to the Adafruit Feather slave. This code can be found in 'void sendData()' below and involves disassembling complex float numbers eg 89.29 and turning them into a string and then using character manipulation to turn them into a seires of individual integer digits, ie 8 ...9 ...2 ...9. To make it even more complicated, each series of integers had to have an identification marker so that the slave could recognise that a particular stream of digits had been initiated and it had to also have a number representing the number of digits being sent (string length) AND, just to completely fry my already half cooked brain, the digits themselves had to be sent back to front!
#include <Adafruit_ADS1015.h> #include <OneWire.h> #include <DallasTemperature.h> #include <Wire.h> #include <LiquidCrystal.h> #define ONE_WIRE_BUS 10 #define TEMPERATURE_PRECISION 12 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress sensor0,sensor1,sensor2,sensor3; char digitCharAAAA[10]; char digitCharBBBB[10]; String testAA; String nothing; // This is important - the string precursor. String testAAAA; // File names need to be of sufficient complexity! String testBBBB; int stringLengthAA; int numberId =101; int dataPrecursor = 198; // A randomish number below 254. Be careful it does not conflict with numberIds. int digitAAAA; float tempZ=20.01; int n = 0; unsigned long currentTime=0; unsigned long previousTime=0; unsigned long intervalTime=0; float tempC; int deviceCount =0; float boilerTemp; float refluxTemp; float hydroTemp; float condensorTemp; float previousTempC =0; float totalTempC=0; float deltaTempC =0; float previousDeltaTempC =0; float doubleDeltaTempC =0; Adafruit_ADS1115 ads; /* Use this for the 16-bit version */ // Adafruit_ADS1015 ads; /* Use thi for the 12-bit version */ LiquidCrystal lcd(12, 11, 5, 4, 3, 2); byte delta[8] = { B00000, B00100, B00100, B01010, B01010, B10001, B11111, B00000 }; byte percent[8] = { B11001, B11010, B00010, B00100, B00100, B01000, B01011, B10011 }; const int analogInPin = A0; // Analog input pin that the potentiometer is attached to const int densityEthanol = 789; long sensorValue = 0; // value read from the pot int outputValue = 0; // value output to the PWM (analog out) int outputValueMin = 1000; int outputValueMax = -1000; int loopToStart =0; int a=0; int i=0; int k=0; int c=0; int x=0; int z=0; int y=5; int h=0; int f=0; int T00=0; int T01=0; int T02=0; int T03=0; int T04=0; int T05=0; float endTemp =0; int alcoholCount=0; float alcoholX=10.00; int alcoholLimit=550; double potReading01=0; double pumpTimer1=0; double pumpTimer2=0; int pumpTimer3=1; int pumpTimer4=0; int adjustmentTimer=200; int mappedPotReading01=0; int potReading02=0; int mappedPotReading02=0; int potReading03=0; double powerFactor=0; int levelSwitch =HIGH; int foreshotsDumpValue =0; int startAndEndDumpValue =0; int tempCount=0; int momentarySwitchStatus =0; int mins=0; double ethanol =0; float av=0; long totalAdjustedOutputValue=0; int adjustedOutputValue = 0; float hrs=1; double pressure =0; double avPressure =0; //Digital pins: //D13: //D12:LCD //D11:LCD //D10:TEMP01 //D09:Relay //D08:Dump relay //D07:Relay for equalising hydrometer pressure //D06:Heater relay //D05:LCD //D04:LCD //D03:LCD //D02:LCD //Analogue pins: //A0:Tone //A1:Pot //A2:Pot //A3:Pot //A7:Alcohol void setup() { pinMode(A8, INPUT_PULLUP); // Boiler level switch pinMode(6, OUTPUT); // Relay for heater digitalWrite(6, LOW); pinMode(8, OUTPUT); // Relay for dump valve. digitalWrite(8, LOW); pinMode (13, OUTPUT); // Relay digitalWrite(13, LOW); pinMode (7, OUTPUT); // Relay digitalWrite(7, LOW); pinMode (9, OUTPUT); // Relay digitalWrite(9, LOW); // External relays: 47,49,51,53 pinMode(47, OUTPUT); // Relay for NOT USED digitalWrite(47, HIGH); pinMode(49, OUTPUT); // Relay for PUMP digitalWrite(49, HIGH); pinMode(51, OUTPUT); // Relay for RH valve digitalWrite(51, HIGH); pinMode(53, OUTPUT); // Relay for LH valve digitalWrite(53, HIGH); // pinMode (A1, OUTPUT); //SFX T02 alcohol levels exceeded // pinMode (A2, OUTPUT); //SFX T03 seventy degrees // pinMode (A3, OUTPUT); //SFX T04 ninety five degrees pinMode (23, OUTPUT); //SFX .............. pinMode (25, OUTPUT); //SFX ..............Finished pinMode (27, OUTPUT); //SFX ..............Alcohol too high pinMode (29, OUTPUT); //SFX ..............70 degrees pinMode (31, OUTPUT); //SFX ..............95 degrees pinMode (33, OUTPUT); //SFX ..............Heater turned on pinMode (35, OUTPUT); //SFX ..............Process initiated pinMode (37, OUTPUT); //SFX ..............Dump valve opened pinMode (39, OUTPUT); //SFX ..............Temperature is rising pinMode (41, OUTPUT); //SFX ..............Now producing alcohol pinMode (43, OUTPUT); //SFX .............. //SFX T06 //SFX T07 // digitalWrite(A1, HIGH); // digitalWrite(A2, HIGH); // digitalWrite(A3, HIGH); digitalWrite(23, HIGH); digitalWrite(25, HIGH); digitalWrite(27, HIGH); digitalWrite(29, HIGH); digitalWrite(31, HIGH); digitalWrite(33, HIGH); digitalWrite(35, HIGH); digitalWrite(37, HIGH); digitalWrite(39, HIGH); digitalWrite(41, HIGH); digitalWrite(43, HIGH); digitalWrite(35, LOW); delay(500); digitalWrite(35, HIGH); // digitalWrite(11, HIGH); Serial.begin(115200); lcd.createChar(1, delta); lcd.createChar(2, percent); lcd.begin(20, 4); lcd.setCursor(0,0); lcd.print(" DISTILLATION "); lcd.setCursor(0,1); lcd.print(" INITIATED "); ////////////////////////////////Wait for MQ3 to warm up ////////////////////////////////////////// delay(3000); alcoholX = analogRead(A7); while (alcoholX>alcoholLimit) { alcoholX = analogRead(A7); tone (A0,alcoholX*2,200); delay(500); lcd.setCursor(0,0); lcd.print("Wait for MQ3 Heater "); lcd.setCursor(0,1); lcd.print(" "); lcd.setCursor(0,2); lcd.print("Alcohol:"); lcd.setCursor(9,2); lcd.print(alcoholX); } ////////////////////////////////////////////////////////////////////////////////////////////////// //Temperature stuff sensors.begin(); // locate devices on the bus Serial.print("Locating devices..."); Serial.print("Found "); deviceCount = sensors.getDeviceCount(), DEC; Serial.print(deviceCount); Serial.println(" devices."); if (!sensors.getAddress(sensor0, 0)) Serial.println("Unable to find address for Device 0"); if (!sensors.getAddress(sensor1, 1)) Serial.println("Unable to find address for Device 1"); if (!sensors.getAddress(sensor2, 2)) Serial.println("Unable to find address for Device 2"); if (!sensors.getAddress(sensor3, 3)) Serial.println("Unable to find address for Device 3"); sensors.setResolution(sensor0, TEMPERATURE_PRECISION); sensors.setResolution(sensor1, TEMPERATURE_PRECISION); sensors.setResolution(sensor2, TEMPERATURE_PRECISION); sensors.setResolution(sensor3, TEMPERATURE_PRECISION); Serial.print("Device 0 Address: "); printAddress(sensor0); Serial.println(); Serial.print("Device 1 Address: "); printAddress(sensor1); Serial.println(); Serial.print("Device 2 Address: "); printAddress(sensor2); Serial.println(); Serial.print("Device 3 Address: "); printAddress(sensor3); Serial.println(); Serial.println(""); printTemperature(); lcdTemperatures(); delay (4000); ////////////////////////////////////////////////////////////////////////////////////////////////// pinMode(28, INPUT_PULLUP); // Momentary switch ads.begin(); previousTempC = tempC; totalTempC = -1*tempC; delay (4000); digitalWrite(8, LOW); lcd.clear(); } /////////////////////////////////////////////////////////////////////////////////////////// void loop() { /////////////////////////////////////////////////////////////////////////////////////////////// // Send data to the Feather Nestbox every 2 minutes: currentTime = millis(); intervalTime = currentTime - previousTime; Serial.print("Current time: "); Serial.print(currentTime/1000); Serial.print(" Secs ");Serial.print(currentTime/60000);Serial.println(" Minutes"); if (intervalTime > 120000) { // Send data to the feather HERE. /////////////////////////////////////////////////////////////////////////////////////////////// Serial.println("Now we are doing a transmission ....... "); Serial.println(""); lcd.setCursor(0,3); lcd.print("Transmitting data..."); delay(3000); Wire.beginTransmission(9); // transmit to device #9 // Make sure the order is the same in master and slave. delay(20); // We're going to send two chunks of data, tempA and tempB. Each of them is less than 1,000 and has two digits after the //decimal place. tempZ=boilerTemp; numberId= 101; sendData(); Serial.print(numberId);Serial.print(": ");Serial.println(tempZ); delay(50); tempZ=refluxTemp; numberId= 102; sendData(); Serial.print(numberId);Serial.print(": ");Serial.println(tempZ); delay(50); tempZ=condensorTemp; numberId= 103; sendData(); Serial.print(numberId);Serial.print(": ");Serial.println(tempZ); delay(50); tempZ=hydroTemp; numberId= 104; sendData(); Serial.print(numberId);Serial.print(": ");Serial.println(tempZ); delay(50); Wire.endTransmission(); Wire.beginTransmission(9); // transmit to device #9 // Make sure the order is the same in master and slave. delay(20); tempZ=mins; numberId= 107; sendData(); delay(20); tempZ=alcoholX/10; numberId= 105; sendData(); Serial.print(numberId);Serial.print(": ");Serial.println(tempZ); tempZ=pressure/10; numberId= 106; sendData(); while (k<20) { tone (A0,700,50); delay(100); k++; } k=0; Serial.print(numberId);Serial.print(": ");Serial.println(tempZ); delay(50); Wire.endTransmission(); Serial.println(""); Serial.println("Transmission ended ....... "); Serial.println(""); previousTime=currentTime; } /////////////////////////////////////////////////////////////////////////////////////////////// int momentarySwitch = digitalRead(28); if ((momentarySwitch == LOW)&&(momentarySwitchStatus == 0)) { momentarySwitchStatus=1; } else { if ((momentarySwitch == LOW)&&(momentarySwitchStatus == 1)) { momentarySwitchStatus=0; } } /////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////// if command encompases all the next code ///////////////////// if (momentarySwitchStatus==0) { //////////////////////////////////////////////////////////////////////////////////////////// // Test external relays //////////////////////////////////////////////////////////////////// // digitalWrite(53, LOW); // delay(5000); // digitalWrite(53, HIGH); /////////////////////////////////////////////////////////////////////////////////////////// //////// A place to allow settings to be adjusted ///////////////////////////////////////// while (adjustmentTimer>0) { tone(A0,(adjustmentTimer*2)+600,50); potReading01 = analogRead(A1); pumpTimer4 = potReading01; lcd.setCursor(0,0); lcd.print("Pump timer:"); lcd.setCursor(12,0); lcd.print(" "); lcd.setCursor(12,0); lcd.print(pumpTimer4); lcd.setCursor(15,0); lcd.print("secs"); lcd.setCursor(0,1); lcd.print("Alcohol limit:"); lcd.setCursor(15,1); lcd.print(alcoholLimit); potReading03 = analogRead(A3); powerFactor = map(potReading03, 14, 1023, 0, 100); lcd.setCursor(0,2); lcd.print("Power factor:"); lcd.setCursor(14,2); lcd.print(powerFactor); lcd.setCursor(18,2); lcd.write(2); potReading02 = analogRead(A2); mappedPotReading02 = map(potReading02, 13, 1023, 0, 1000); endTemp = (mappedPotReading02 / 200.00) + 98.00; lcd.setCursor(0,3); lcd.print("End Temp: "); lcd.setCursor(10,3); lcd.print(endTemp,2); lcd.setCursor(16,3); lcd.print("\337C"); adjustmentTimer=adjustmentTimer-1; delay(100); } ///////////////////////////////// Reading potentiometer on A1: Unused /////////////////////// if (loopToStart ==0) { lcd.clear(); potReading01 = analogRead(A1); lcd.setCursor(0,2); lcd.print("Pump in timer:"); lcd.setCursor(5,3); pumpTimer4 = potReading01; lcd.print(pumpTimer4); lcd.print(" seconds "); } //////////////////////////////////////////////////////////////////////////////////////////// ///// Empty the boiler. Fluid exits from LH valve port 3 /////////////////////////////////// pumpTimer1 = 1000*potReading01; pumpTimer2 = 1000*potReading01; if (loopToStart ==0) { //Pump and valves: //Valve default state is port 1 to 3 open. while (pumpTimer1>0) { levelSwitch = digitalRead(A8); if (levelSwitch == HIGH) { tone(A0,800,500); Serial.print("Level switch: "); Serial.println(levelSwitch); } pumpTimer1=pumpTimer1-1000; lcd.setCursor(0,0); lcd.print(" PUMPING OUT "); lcd.setCursor(0,1); lcd.print(" "); lcd.setCursor(5,1); pumpTimer3 = pumpTimer1/1000; lcd.print(pumpTimer3); digitalWrite(49, LOW); // Pump delay(1000); //Effectively mappedPotReading01 is in seconds. } lcd.setCursor(0,1); lcd.print(" COMPLETED "); digitalWrite(49, HIGH); } delay(5000); ///////////////////////////////////////////////////////////////////////////////////////// ///// Fill the boiler. Fluid enters from RH valve port 2 //////////////////////////////// pumpTimer3 =1; if ((loopToStart ==0)&&(pumpTimer3>0)) // &&(levelSwitch==LOW) { // digitalWrite(49, LOW); // Pump // digitalWrite(51, LOW); // LH valve digitalWrite(53, LOW); // RH valve must be opened before the pump starts. // delay(5000); // digitalWrite(49, HIGH); // digitalWrite(51, HIGH); // digitalWrite(53, HIGH); delay(2000); while ((pumpTimer3>0) && (levelSwitch==LOW)) { levelSwitch = digitalRead(A8); tone(A0,800,500); pumpTimer2=pumpTimer2-1000; lcd.setCursor(0,2); lcd.print(" PUMPING IN "); lcd.setCursor(0,3); lcd.print(" "); lcd.setCursor(5,3); pumpTimer3 =pumpTimer2/1000; lcd.print(pumpTimer3); lcd.setCursor(9,3); lcd.print(" Seconds "); digitalWrite(49, LOW); // Pump digitalWrite(51, LOW); //LH valve digitalWrite(53, LOW); delay(1000); } } if (loopToStart ==0) { lcd.setCursor(0,3); lcd.print(" COMPLETED "); digitalWrite(49, HIGH); digitalWrite(51, HIGH); digitalWrite(53, HIGH); delay(5000); lcd.clear(); } loopToStart=1; // This stops the pumping processes repeating in every loop. /////////////////////////////////////////////////////////////////////////////////// ///// Dump the contents of the hydrometer at the start //////////////////////////// startAndEndDump(); /////////////////////////////////////////////////////////////////////////////////// ////////////////// Changes the Beep when alcohol starts to be produced //////////// if (pressure < 400) { tone (A0,tempC*40,500); } else { k=10; while (k<20) { tone (A0,tempC*k,50); delay(50); k++; } if (a==0) // One off Producing alcohol SFX. { digitalWrite(41, LOW); delay(500); digitalWrite(41, HIGH); a=1; } } ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////// Reading potentiometer on A2: End point temperature //////// potReading02 = analogRead(A2); mappedPotReading02 = map(potReading02, 13, 1023, 0, 1000); endTemp = (mappedPotReading02 / 200.00) + 98.00; delay(100); lcd.setCursor(0,0); lcd.print("End Temp: "); lcd.setCursor(11,0); lcd.print(endTemp,2); lcd.setCursor(18,0); lcd.print("\337C"); // Serial.println(endTemp,2); /////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////// Reading potentiometer on A3: Heater power factor % ////// potReading03 = analogRead(A3); powerFactor = map(potReading03, 14, 1023, 0, 100); lcd.setCursor(0,1); lcd.print("Power factor: "); lcd.setCursor(14,1); lcd.print(powerFactor); lcd.setCursor(18,1); lcd.write(2); ///////////////////////////////////// Row 4 of LCD //////////////////////////////////////// lcd.setCursor(0,3); lcd.print(" "); ////////////////////////////////////////////////////////////////////////////////////////// delay (1000); lcdStuff(); ///////////////////////////////// Now producing alcohol SFX ////////////////////////////// if ((tempCount==30)&&(pressure>100)) { digitalWrite(41, LOW); delay(500); digitalWrite(41, HIGH); } Serial.print("tempcount: ");Serial.println(tempCount); ///////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////// The process needs to finish //////////////////////////////// if (tempC > endTemp) { digitalWrite(6, LOW); // startAndEndDumpValue=0; // startAndEndDump(); while (1) { lcd.setCursor(0,0); lcd.print(" FINISHED "); digitalWrite(25,LOW); delay(1000); digitalWrite(25,HIGH); delay(10000); } } else { digitalWrite(A0,HIGH); } ///////////////////////////////////////////////////////////////////////////////////////////// alcoholX = analogRead(A7)*1.01; Serial.print("Alcohol: ");Serial.println(alcoholX); if (alcoholX>alcoholLimit) { while (alcoholX>alcoholLimit) { digitalWrite(6, LOW); lcdStuff(); alcoholX = analogRead(A7); digitalWrite(27, LOW); // SFX delay(500); digitalWrite(27, HIGH); delay (10000); } } else { digitalWrite(A1, HIGH); } if (alcoholX<alcoholLimit) { alcoholCount++; } else { alcoholCount=0; } ///////////////////////////////////////////////////////////////////////////////////////////// /////////// Heater control for full power://///////////////////////////////////////////////// if ((alcoholX<650)&&(alcoholCount>5)&&(tempC<85)) { digitalWrite(6, HIGH); if (T05==0) // Make a one off audio sound { digitalWrite(33, LOW); delay(500); digitalWrite(33, HIGH); T05=1; lcd.clear(); } } // else // { // digitalWrite(6, LOW); // T05=0; // } ///////////////////////////////////////////////////////////////////////////////////////////// /////////// Heater control for 1/5 power://////////////////////////////////////////////////// if ((alcoholX<650)&&(alcoholCount>10)&&(tempC>85)&&(condensorTemp<50)) { digitalWrite(6, LOW); delay (1000); digitalWrite(6, HIGH); delay (powerFactor*250); digitalWrite(6, LOW); } Serial.print("Power Factor: "); Serial.println(powerFactor,2); // else // { // digitalWrite(6, LOW); // } ////////////////////////////////////////////////////////////////////////////////////////// if (condensorTemp>50) { digitalWrite(6, LOW); lcd.setCursor(0,3); lcd.print("Condensor too hot"); } ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////// One off SFX /////////////////////////////////////////// if ((tempC>70)&&(T03==0)) { digitalWrite(29, LOW); delay(500); digitalWrite(29, HIGH); T03=1; } else { digitalWrite(A2, HIGH); } /////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////// One off SFX /////////////////////////////////////////// if ((tempC>95)&&(T04==0)) { digitalWrite(31, LOW); delay(500); digitalWrite(31, HIGH); T04=1; } else { digitalWrite(A3, HIGH); } ///////////////////////////////////////////////////////////////////////////////////////// foreshotsDump(); //////////////////////////////////////////////////////////////////////////////////////// if (f==5) { pressureZeroing(); } sensors.requestTemperatures(); // Send the command to get temperatures printTemperature(); totalTempC = totalTempC + tempC; ///////////////////////////////////////////////////////////////////////////////////////// int pushButton = digitalRead(10); if (pushButton == HIGH) { // Serial.print("Switch Off"); digitalWrite(8, LOW); } else { // Serial.print("Switch On"); // pressureZeroing(); digitalWrite(8, HIGH); } // Serial.println(" "); ////////////////////////////////////////////////////////////////////////////////////////// ///////// Reading the hydrometer pressure sensor //////////////////////////////////////// int16_t adc0, adc1, adc2, adc3; // adc0 = ads.readADC_SingleEnded(0); // Serial.print("AIN0: "); Serial.println(adc0); // Serial.println(" "); i=0; c++; sensorValue =0; while (i<15) { adc0 = analogRead(11); i++; sensorValue = sensorValue + adc0; delay (50); } sensorValue = sensorValue/i; // sensorValue = adc0; // Map it to the range of the analog out: //outputValue = map(sensorValue, 0, 1024, -2500, 2500); adjustedOutputValue = (sensorValue-512)*2.2; // Needs to be active in the range 0 to 1,000. pressure = adjustedOutputValue; Serial.print("Pressure sensor = "); // The sensor usually reads about 512 ie 1024/2. Serial.print(sensorValue); Serial.print("\t Actual output = "); Serial.println(pressure); if (adjustedOutputValue > outputValueMax) { outputValueMax = adjustedOutputValue; } if (adjustedOutputValue < outputValueMin) { outputValueMin = adjustedOutputValue; } totalAdjustedOutputValue = adjustedOutputValue + totalAdjustedOutputValue; av = 1.000*totalAdjustedOutputValue/c; avPressure = av/1.607/1.284; ethanol = 100 - (avPressure - densityEthanol) / (1000 - densityEthanol) *100; mins = c/60; /////////////////////////////////////////////////////////////////////////////////////////////// ////////////// Calculating the temperature changes value (delta T) //////////////////////////// if (tempCount ==10) { deltaTempC = totalTempC/10 - previousTempC; previousTempC = totalTempC/10; doubleDeltaTempC = deltaTempC - previousDeltaTempC; previousDeltaTempC = deltaTempC; if (deltaTempC >0.2) { digitalWrite(39, LOW); // SFX (Temperature is rising .... Checking all systems are operational.) delay(500); digitalWrite(39, HIGH); } // Serial.print(k); // Serial.print(","); // Serial.print(totalTempC/60); // Serial.print(","); // Serial.print(deltaTempC); // Serial.print(","); // Serial.println(pressure,0); // Serial.print("Ethanol%: "); // Serial.println(ethanol,0); z=10; y=0; totalTempC=0; /////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////// Zeroing the hydrometer sensor at 70 degrees C ///////////////////// if ((tempC>70)&&(h<1)) { pressureZeroing(); h=1; } tempCount=0; k++; } ////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////// Print to LCD ///////////////////////////////////////////////////// lcdTemperatures(); delay(5000); lcdStuff(); delay(5000); tempCount++; f++; } ////// The curly bracket above is effectively the main loop except for small bit of code below /// ///////////////////////////////////////////////////////////////////////////////////////////////// ////////////////// Momentary switch stuff below here //////////////////////////////////////////// else { paused(); delay(1000); } } /////////////////////////////////////////////////////////////////////////////////////////////// void paused() { digitalWrite(6, LOW); // Turn off heater. digitalWrite(8, LOW); // Close dump valve. alcoholX = analogRead(A7); sensors.requestTemperatures(); // Send the command to get temperatures printTemperature(); lcd.setCursor(0,0); lcd.print(" PAUSED "); lcd.setCursor(0,1); lcd.print(" "); lcd.setCursor(0,2); lcd.print(" "); lcd.setCursor(0,3); lcd.print(" "); lcd.setCursor(0,0); lcd.print("P:"); delay(10); lcd.setCursor(2,0); lcd.print(pressure,0); lcd.setCursor(0,1); lcd.print("Max:"); lcd.setCursor(4,1); lcd.print(outputValueMax); lcd.setCursor(0,2); lcd.print("Alc:"); delay(10); lcd.setCursor(4,2); lcd.print(alcoholX); lcd.setCursor(0,3); lcd.print("Secs:"); lcd.setCursor(5,3); lcd.print(c); lcd.setCursor(11,3); delay(10); lcd.print("Mins:"); lcd.setCursor(16,3); lcd.print(mins,1); lcd.setCursor(11,1); lcd.print("A:"); delay(10); lcd.setCursor(11,2); lcd.print("T:"); lcd.setCursor(13,2); lcd.print(tempC); lcd.setCursor(18,2); lcd.print("\337C"); } void printTemperature() { Serial.println(" "); sensors.requestTemperatures(); Serial.print("Boiler Temp: "); boilerTemp =sensors.getTempCByIndex(1)-0.76; // Change the index value accordingly. Serial.println(boilerTemp); sensors.requestTemperatures(); Serial.print("Reflux Temp: "); refluxTemp =sensors.getTempCByIndex(2)-0.76; // Change the index value accordingly. Serial.println(refluxTemp); sensors.requestTemperatures(); Serial.print("Condensor Temp: "); condensorTemp =sensors.getTempCByIndex(0)-0.76; // Change the index value accordingly. Serial.println(condensorTemp); sensors.requestTemperatures(); Serial.print("Hydrometer Temp: "); hydroTemp =sensors.getTempCByIndex(3)-0.76; // Change the index value accordingly. Serial.println(hydroTemp); Serial.println(" "); tempC=boilerTemp; } void pressureZeroing() { x = outputValue; outputValueMin = 10000; outputValueMax = -10000; c = 0; totalAdjustedOutputValue =0; av=0; hrs=0; } void lcdTemperatures() { lcd.setCursor(0,0); lcd.print("Boiler Temp:"); lcd.setCursor(12,0); lcd.print(" "); lcd.setCursor(12,0); lcd.print(boilerTemp,2); lcd.setCursor(18,0); lcd.print("\337C"); lcd.setCursor(0,1); lcd.print("Reflux Temp:"); lcd.setCursor(12,1); lcd.print(refluxTemp,2); lcd.setCursor(18,1); lcd.print("\337C"); lcd.setCursor(0,2); lcd.print("Conden Temp:"); lcd.setCursor(12,2); lcd.print(condensorTemp,2); lcd.setCursor(18,2); lcd.print("\337C"); lcd.setCursor(0,3); lcd.print("Hydrom Temp:"); lcd.setCursor(12,3); lcd.print(hydroTemp,2); lcd.setCursor(18,3); lcd.print("\337C"); } void lcdStuff() { lcd.setCursor(0,0); lcd.print(" "); lcd.setCursor(0,1); lcd.print(" "); lcd.setCursor(0,2); lcd.print(" "); lcd.setCursor(0,3); lcd.print(" "); lcd.setCursor(0,0); lcd.print("P:"); delay(10); lcd.setCursor(2,0); lcd.print(pressure,0); lcd.setCursor(11,0); lcd.write(1); lcd.print("T:"); lcd.setCursor(14,0); lcd.print(deltaTempC); lcd.setCursor(0,1); lcd.print("Max:"); lcd.setCursor(4,
-
15Step 15
Adafruit GPRS Feather Code
The crux of this code is the 'unravelData()' function which receives the stream of data and turns it into a character arrays called 'rabbits'. These arrays are then pretty much ready to be passed over to the FONA module for transmission down the GPRS network via a PHP 'Get' command. No real animals are sent down the I2C bus!!
Whilst on the subject of rabbits, an analogy would be where two foxes are working together on different sides of a hedge. The first fox chops the rabbits up into legs, arms, head, ears etc and sends everything down the rabbit hole tail first, ears last. The fox on the other side of the hedge is feeling benevolent and puts the rabbits back together again, but needs to know which rabbit is which and how many parts each rabbit was chopped up into as some rabbits were bigger than others.
#include <Wire.h> #include "Adafruit_FONA.h" #define FONA_RX 9 #define FONA_TX 8 #define FONA_RST 4 #define FONA_RI 7 // this is a large buffer for replies char replybuffer[255]; String initiator; String dataString; const char webAddress[100] = "http://www.goatindustries.co.uk/test/send.php?"; char url[120]; String nothing; int numberId =0; String resultForNumberId; String numberA; int stringLength =0; String testad; float result101=0.00; float result102=0.00; float result103=10.00; float result104=20.00; float result105=30.00; float result106=40.00; float result107=50.00; int n=0; int i=0; String compileA; char rabbits[10]; int a; int k; int z=0; #include <SoftwareSerial.h> SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX); SoftwareSerial *fonaSerial = &fonaSS; //Connect Rx on Fona to Tx1 on mega or due: //HardwareSerial *fonaSerial = &Serial1; Adafruit_FONA fona = Adafruit_FONA(FONA_RST); uint8_t readline(char *buff, uint8_t maxbuff, uint16_t timeout = 0); uint8_t type; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// void setup() { Serial.begin(115200); pinMode(10,OUTPUT); digitalWrite(10, HIGH); delay(1000); digitalWrite(10, LOW); pinMode(13, OUTPUT); ledFastFlash(); ledFastFlashB(); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Wire.begin(9); // join i2c bus with address #9 Wire.onReceive(receiveEvent); // register event /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // while (!Serial); // Use this for initiating program by opening of serial monitor. Delete in normal operation. Serial.println(F("FONA basic test")); Serial.println(F("Initialiking....(May take 3 seconds)")); fonaSerial->begin(4800); if (! fona.begin(*fonaSerial)) { Serial.println(F("Couldn't find FONA")); // while (1); } type = fona.type(); Serial.println(F("FONA is OK")); Serial.print(F("Found ")); switch (type) { case FONA800H: Serial.println(F("FONA 800H")); break; } networkStatus(); // Check the network is available. Home is good. Serial.println(""); Serial.println("Checking that GPRS is turned off to start with ........."); fona.setGPRSNetworkSettings(F("pp.vodafone.co.uk"), F("wap"), F("wap")); // Change these settings! (Network APN, username ,password) delay (1000); // Turn off GPRS: if (!fona.enableGPRS(false)) Serial.println(F("No - Failed to turn off")); Serial.println("If the line above says OK, then GPRS has just been turned off"); delay (1000); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Serial.println("Waiting for data from i2c ..........."); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void loop() { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (z>0) // This loop is initiated if z is greater than 1. The value of z is given by the reciept of I2C data { ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// delay(5000); Serial.print(F("FONA> ")); networkStatus(); // Check the network is available. Home is good. ledFastFlash(); turnOnGPRS(); turnOnGPRS(); ledSlowFlash(); Serial.println(""); Serial.print("Result 101: ");Serial.println(result101,2); Serial.print("Result 102: ");Serial.println(result102,2); Serial.print("Result 103: ");Serial.println(result103,2); Serial.print("Result 104: ");Serial.println(result104,2); Serial.print("Result 105: ");Serial.println(result105,2); Serial.print("Result 106: ");Serial.println(result106,2); Serial.print("Result 107: ");Serial.println(result107,2); // read website URL uint16_t statuscode; int16_t length; char url[180]; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // This is where the data is compiled into a character .... dataString = initiator + webAddress + "tempA="+result101 + "&tempB="+result102 + "&tempC="+result103 + "&tempD="+result104 + "&alcohol="+result105 + "&pressure="+result106 + "&minutes="+result107; // To add another temperature reading we would need: +"&tempB="+tempB int n = dataString.length(); Serial.print("Data string to send: ");Serial.println(dataString); Serial.print("Size of string: ");Serial.println(n); // Builds the url character: for (int aa=0;aa<=n;aa++) { url[aa] = dataString[aa]; } Serial.print("Character data to send: ");Serial.println(url); Serial.println(""); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //..... and sent out via HTTP to a PHP file called send.php ready to recieve it. Serial.print("Sending url .... "); Serial.print("Compiled url is: ");Serial.println(url); Serial.println(F("****")); if (!fona.HTTP_GET_start(url, &statuscode, (uint16_t *)&length)) { Serial.println("Failed!"); } while (length > 0) { while (fona.available()) { char c = fona.read(); // Serial.write is too slow, we'll write directly to Serial register! #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */ UDR0 = c; #else // digitalWrite(5, HIGH); // Call back to Master to say that tranmission was successful. Serial.write(c); //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #endif length--; if (! length) break; } } Serial.println(F("\n****")); fona.HTTP_GET_end(); Serial.println("Wait for 10 seconds ..........."); delay (10000); // Turn off GPRS: if (!fona.enableGPRS(false)) Serial.println(F("No - Failed to turn off")); Serial.println("GPRS turned off?"); while (fona.available()) { Serial.write(fona.read()); } z=0; Serial.println("Waiting for data from i2c ..........."); } } // End of main loop. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void turnOnGPRS() { delay (10000); Serial.println("Now attempting to turn on GPRS ........."); // if (!fona.enableGPRS(true)) // Serial.println(F("No - Failed to turn on")); // Serial.println("GPRS is on if the line above shows 'OK'"); // Serial.println("Wait for 10 seconds to make sure GPRS is on ..........."); // delay (10000); if (fona.enableGPRS(true)) ledFastFlashB(); // Indicates a connect to GPRS. //Serial.println(("No - Failed to turn on")); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void networkStatus() { //delay(10000); // read the network/cellular status uint8_t n = fona.getNetworkStatus(); Serial.print(F("Network status ")); Serial.print(n); Serial.print(F(": ")); if (n == 0) Serial.println(F("Not registered")); if (n == 1) Serial.println(F("Registered (home)")); if (n == 2) Serial.println(F("Not registered (searching)")); if (n == 3) Serial.println(F("Denied")); if (n == 4) Serial.println(F("Unknown")); if (n == 5) Serial.println(F("Registered roaming")); } void receiveEvent(int bytes) { //delay(5000); // wait for data to be sent. a=20; while (a>0) // This looks for the correct numberId to iniate the next if command. { numberId = Wire.read(); // Serial.print("Possible number Id: ");Serial.println(numberId); n=-1; compileA = nothing; testad = nothing; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Serial.println(""); if (numberId==101) { unravelData(); result101 = (rabbits+nothing).toInt()/100.00; } if (numberId==102) { unravelData(); result102 = (rabbits+nothing).toInt()/100.00; } if (numberId==103) { unravelData(); result103 = (rabbits+nothing).toInt()/100.00; } if (numberId==104) { unravelData(); result104 = (rabbits+nothing).toInt()/100.00; } if (numberId==105) { unravelData(); result105 = (rabbits+nothing).toInt()/100.00; } if (numberId==106) { unravelData(); result106 = (rabbits+nothing).toInt()/100.00; } if (numberId==107) { unravelData(); result107 = (rabbits+nothing).toInt()/100.00; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////// a--; delay(100); } delay(10); z=1; // recieveEvent is on an interrupt so when it's triggered it changes z to 1 and allows main loop. } //////////////////////////////////////////////////////////////////////////////////////////////////////// void unravelData() { a=10; stringLength = Wire.read(); while (n<stringLength) { compileA = testad + compileA; testad = nothing + Wire.read(); // This is a string. n++; // Serial.print("Compile: ");Serial.println(compileA); } numberA = compileA; // Serial.print("NumberA: ");Serial.println(numberA); // Serial.print("String length: ");Serial.println(stringLength); //Builds the rabbits character: i=stringLength; for (int aa=0;aa<=i;aa++) { rabbits[aa] = compileA[aa]; } //Now create a string in which the last 3 characters represent the ID. //The string can have the last four characters removed before being processed at the next stage. resultForNumberId = nothing + rabbits +" & " + numberId; // Serial.print("rabbits: ");Serial.println(rabbits); // Serial.print("Result for number Id: ");Serial.print(numberId); Serial.print(" is: "); Serial.println(resultForNumberId ); Serial.println(""); } void ledSlowFlash() { digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level) delay(1000); // wait for a second digitalWrite(13, LOW); // turn the LED off by making the voltage LOW } void ledFastFlash() { k=0; while(k<20) { digitalWrite(13, HIGH); // turn the LED on (HIGH is the voltage level) delay(100); // wait for a second digitalWrite(13, LOW); // turn the LED off by making the voltage LOW delay(100); k++; } } void ledFastFlashB() { k=0; while(k<20)
-
16Step 16
License:
Creative Commons Attribution-ShareAlike 4.0 International Public LicenseBy exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.
Section 1 – Definitions.
- Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
- Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.
- BY-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License.
- Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
- Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
- Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
- License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution and ShareAlike.
- Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License.
- Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
- Licensor means the individual(s) or entity(ies) granting rights under this Public License.
- Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.
- Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
- You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.
Section 2 – Scope.
- License grant.
- Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
- reproduce and Share the Licensed Material, in whole or in part; and
- produce, reproduce, and Share Adapted Material.
- Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
- Term. The term of this Public License is specified in Section 6(a).
- Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
- Downstream recipients.
- Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
- Additional offer from the Licensor – Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply.
- No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.
- No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).
- Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
- Other rights.
- Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.
- Patent and trademark rights are not licensed under this Public License.
- To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties.
Section 3 – License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the following conditions.
- Attribution.
- If You Share the Licensed Material (including in modified form), You must:
- retain the following if it is supplied by the Licensor with the Licensed Material:
- identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
- a copyright notice;
- a notice that refers to this Public License;
- a notice that refers to the disclaimer of warranties;
- a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
- indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
- indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
- retain the following if it is supplied by the Licensor with the Licensed Material:
- You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.
- If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.
- If You Share the Licensed Material (including in modified form), You must:
- ShareAlike. In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply.
- The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-SA Compatible License.
- You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material.
- You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply.
Section 4 – Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:
- for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database;
- if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and
- You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.
Section 5 – Disclaimer of Warranties and Limitation of Liability.
- Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.
- To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.
- The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
Section 6 – Term and Termination.
- This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.
- Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
- automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or
- upon express reinstatement by the Licensor.
- For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
- Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
Section 7 – Other Terms and Conditions.
- The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.
- Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.
Section 8 – Interpretation.
- For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.
- To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.
- No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
- Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.