Last active
March 6, 2016 18:55
-
-
Save kenci/78840ac886fcffdf3e10 to your computer and use it in GitHub Desktop.
MySensors
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| PROJECT: MySensors / LiON charger board | |
| PROGRAMMER: AWI | |
| DATE: 28 april 2015/ last update: 11 may 2015 / BH1750 added: 5 September 2015 | |
| FILE: MS_Solar_2.ino | |
| LICENSE: Public domain | |
| Hardware: Ceech - ATmega328p board w/ ESP8266 and NRF24l01+ socket LTC4067 lithium battery charger | |
| and MySensors 1.4 | |
| Temp & Humidity - HTU21 | |
| Barometer & Temp - BMP085 | |
| Light sensor - BH1750 | |
| On board EEPROM (I2C) | |
| On board Li-On charger with multiple V/A measurements | |
| Special: | |
| program with Arduino Pro 3.3V 8Mhz | |
| SUMMARY: | |
| Reads on-board sensors and send to gateway /controller | |
| Remarks: | |
| On board EEPROM and MOSFET not used in this sketch | |
| Fixed node-id | |
| */ | |
| #include <SPI.h> | |
| #include <MySensor.h> | |
| #include <Wire.h> // I2C | |
| #include <BH1750FVI.h> | |
| #define LTC4079_CHRG_PIN A7 //analog input A7 on ATmega 328 is /CHRG signal from LTC4067 | |
| #define batteryVoltage_PIN A0 //analog input A0 on ATmega328 is battery voltage ( /2) | |
| #define solarVoltage_PIN A2 //analog input A2 is solar cell voltage (/ 2) | |
| #define solarCurrent_PIN A6 //analog input A6 is input current ( I=V/Rclprog x 1000 ) | |
| const float VccMin = 1.0*3.5; // Minimum expected Vcc level, in Volts. Example for 1 rechargeable lithium-ion. | |
| const float VccMax = 1.0*4.2; // Maximum expected Vcc level, in Volts. | |
| #define NODE_ID 61 | |
| #define TEMPERATURE_CHILD_ID 2 | |
| #define BATT_CHILD_ID 10 | |
| #define SOLAR_CHILD_ID 11 | |
| #define LIGHT_CHILD_ID 6 | |
| BH1750FVI lightSensor; // define light sensor | |
| #define LUX_THRESHOLD 5 | |
| MySensor gw; // Ceech board, 3.3v pin 7,8 in MySensors config (pin default 9,10) | |
| unsigned long SLEEP_TIME = 60000; // 60 sec sleep time between reads (seconds * 1000 milliseconds) | |
| float lastBattVoltage; | |
| float lastSolarVoltage; | |
| float lastSolarCurrent; | |
| int lastBattPct = 0; | |
| uint16_t lastLux = 0; | |
| float VccReference = 3.3 ; // voltage reference for measurement, definitive init in setup | |
| float vout = 0.0; | |
| float vin = 0.0; | |
| float R1 = 47000.0; // resistance of R1 | |
| float R2 = 10000.0; // resistance of R2 | |
| int value = 0; | |
| int CHRG = A7; | |
| MyMessage batteryVoltageMsg(BATT_CHILD_ID, V_VOLTAGE); // Battery voltage (V) | |
| MyMessage solarVoltageMsg(SOLAR_CHILD_ID, V_VOLTAGE); // Solar voltage (V) | |
| MyMessage solarCurrentMsg(SOLAR_CHILD_ID, V_CURRENT); // Solar current (A) | |
| MyMessage luxMsg(LIGHT_CHILD_ID, V_LIGHT_LEVEL); // Light sensor (lux) | |
| void setup() | |
| { | |
| gw.begin(NULL, NODE_ID); // fixed node 30 | |
| //gw.begin(NULL, NODE_ID, true); //Repeater nodes | |
| // Send the sketch version information to the gateway and Controller | |
| gw.sendSketchInfo("Lichtsensor Terrasse", "2.2"); | |
| gw.present(BATT_CHILD_ID, S_POWER); // Battery parameters | |
| gw.present(SOLAR_CHILD_ID, S_POWER); // Solar parameters | |
| gw.present(LIGHT_CHILD_ID, S_LIGHT_LEVEL); // Light sensor | |
| // use VCC (3.3V) reference | |
| analogReference(DEFAULT); // default external reference = 3.3v for Ceech board | |
| VccReference = 3.354 ; // measured Vcc input (on board LDO) | |
| Wire.begin(); // init I2C | |
| while (lightSensor.begin() != true) | |
| { | |
| Serial.println(F("")); | |
| Serial.println(F("ROHM BH1750FVI Ambient Light Sensor is not present")); | |
| delay(1000); | |
| } | |
| } | |
| void loop() | |
| { | |
| if(sendLight()) { | |
| Serial.println("SENDING..."); | |
| sendVoltage(); | |
| } | |
| Serial.println(); | |
| gw.sleep(SLEEP_TIME); | |
| // By calling process() you route messages in the background | |
| //gw.process(); | |
| } | |
| void sendVoltage(void) | |
| // battery and charging values | |
| { | |
| value = analogRead(solarVoltage_PIN); | |
| vout = (value * VccReference) / 1024.0; | |
| vin = vout / (R2/(R1+R2)); | |
| if (vin<0.09) | |
| { | |
| vin=0.0; | |
| } | |
| // get Battery Voltage & charge current | |
| float batteryVoltage = ((float)analogRead(batteryVoltage_PIN)* VccReference/1024) * 2; // actual voltage is double | |
| Serial.print("Batt: "); | |
| Serial.print(batteryVoltage); | |
| Serial.print("V ; "); | |
| // get Solar Voltage & charge current | |
| float solarVoltage = vin; | |
| Serial.print("Solar: "); | |
| Serial.print(solarVoltage); | |
| Serial.print("V ; "); | |
| // get Solar Current | |
| float solarCurrent = ((float)analogRead(solarCurrent_PIN)* VccReference)/ 3.3; // current(mA) = V/Rclprog(kohm) | |
| Serial.print(solarCurrent); | |
| Serial.print(" mA; charge: "); | |
| Serial.println((float)analogRead(A7)?"No":"Yes"); | |
| // send battery percentage for node | |
| int battPct = 1 ; | |
| if (batteryVoltage > VccMin){ | |
| battPct = 100.0*(batteryVoltage - VccMin)/(VccMax - VccMin); | |
| } | |
| Serial.print("BattPct: "); | |
| Serial.print(battPct); | |
| Serial.println("% "); | |
| gw.send(batteryVoltageMsg.set(batteryVoltage, 3)); // Send (V) | |
| gw.send(solarVoltageMsg.set(solarVoltage, 3)); // Send (V) | |
| gw.send(solarCurrentMsg.set(solarCurrent, 3)); // Send (mA) | |
| gw.sendBatteryLevel(battPct-4); | |
| } | |
| bool sendLight(void) | |
| // Send light level - BH1750 | |
| { | |
| lightSensor.setSensitivity(2); | |
| uint16_t lux = lightSensor.readLightLevel(); | |
| //float diffLux = abs(lux-lastLux); | |
| if (lux != lastLux) { | |
| lastLux = lux; | |
| gw.send(luxMsg.set(lux)); // Send | |
| return true; | |
| } | |
| Serial.print("BH1750 lux: "); | |
| Serial.print(lux); | |
| Serial.println(); | |
| //Serial.print("Diff: "); | |
| //Serial.print(diffLux); | |
| return false; | |
| } | |
| /* Ceech board specifics for reference: | |
| It provides power for the circuit and charges the backup single-cell lithium battery while greatly extends battery life. You can monitor the voltages and currents. It has suspend mode, which reduces current consumption to around 40μA. The power source is a small, 5V solar cell. Connections: | |
| analog input A1 on ATmega 328 is /CHRG signal from LTC4067 (indicates fully charged) | |
| analog input A0 on ATmega328 is battery voltage | |
| analog input A2 is solar cell voltage | |
| analog input A6 is input current ( I=V/Rclprog x 1000 ) | |
| analog input A7 is battery charge current ( I=V/Rprog x 1000 ) | |
| digital output D9 - drive it high to put LTC4067 in SUSPEND mode | |
| All the voltages on analog inputs can be read with an analogRead() command in the Arduino IDE sketch. Those on inputs A0 an A2 represent direct values of the measured voltages divided by 2. The voltages on analog inputs A6 and A7 can be translated to currents. For example: | |
| Let us say that the voltage on A7 is 0.12V. And the trimmer pot on PROG pin is set to 2.5kOhm. This means that the current into the battery equals to 0.12V/2500ohm x 1000, which is 48mA. | |
| voltmeters on both battery and solar cell connections | |
| They are connected to analog inputs A0 and A2 on the ATmega328p. The voltage dividers resistors are equal, so the measured voltage is double the shown voltage. | |
| NRF24l01+ socket | |
| with CE and CSN pins connected to digital pins 7 and 8 ( you use RF24 radio(7, 8); in Arduino code). There is a 4.7uF capacitor connected across Vin and GND of the port | |
| */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* Sketch with Si7021 and battery monitoring. | |
| by m26872, 20151109 | |
| */ | |
| #include <MySensor.h> | |
| #include <Wire.h> | |
| #include <SI7021.h> | |
| #include <SPI.h> | |
| #include <RunningAverage.h> | |
| #include <Vcc.h> | |
| //#include <Bounce2.h> | |
| #define DEBUG | |
| #ifdef DEBUG | |
| #define DEBUG_SERIAL(x) Serial.begin(x) | |
| #define DEBUG_PRINT(x) Serial.print(x) | |
| #define DEBUG_PRINTLN(x) Serial.println(x) | |
| #else | |
| #define DEBUG_SERIAL(x) | |
| #define DEBUG_PRINT(x) | |
| #define DEBUG_PRINTLN(x) | |
| #endif | |
| #define NODE_ID 22 // <<<<<<<<<<<<<<<<<<<<<<<<<<< Enter Node_ID | |
| #define SKETCH_INFO "TempReed SZ" | |
| #define SKETCH_VERSION "3.0 06032016" | |
| #define CHILD_ID_TEMP 0 | |
| #define CHILD_ID_HUM 1 | |
| //Reed | |
| #define CHILD_ID_REED 2 | |
| #define REED_BUTTON_PIN 2 // Arduino Digital I/O pin for button/reed switch | |
| // #define SLEEP_TIME 5000 // 15s for DEBUG | |
| #define SLEEP_TIME 300000 // 5 min | |
| #define FORCE_TRANSMIT_CYCLE 36 // 5min*12=1/hour, 5min*36=1/3hour | |
| #define BATTERY_REPORT_CYCLE 2880 // Once per 5min => 12*24*7 = 2016 (one report/week) | |
| //#define VMIN 1.70 | |
| //#define VMAX 3.24 | |
| #define HUMI_TRANSMIT_THRESHOLD 1.0 // THRESHOLD tells how much the value should have changed since last time it was transmitted. | |
| #define TEMP_TRANSMIT_THRESHOLD 0.5 | |
| #define AVERAGES 2 | |
| const float vccMin = 1.70; // Minimum expected Vcc level, in Volts. | |
| const float vccMax = 3.24; | |
| const float vccCorrection = 3.35/3.31; // Measured Vcc by multimeter divided by reported Vcc | |
| Vcc vcc(vccCorrection); | |
| int batteryReportCounter = BATTERY_REPORT_CYCLE - 1; // to make it report the first time. | |
| int measureCount = 0; | |
| float lastTemperature = -100; | |
| int lastHumidity = -100; | |
| // Reed Switch | |
| //Bounce debouncer = Bounce(); | |
| int oldValue=-1; | |
| // | |
| RunningAverage raHum(AVERAGES); | |
| SI7021 humiditySensor; | |
| MySensor gw; | |
| MyMessage msgTemp(CHILD_ID_TEMP,V_TEMP); // Initialize temperature message | |
| MyMessage msgHum(CHILD_ID_HUM,V_HUM); | |
| MyMessage msgReed(CHILD_ID_REED,V_TRIPPED); | |
| void setup() { | |
| DEBUG_SERIAL(9600); | |
| DEBUG_PRINTLN("Serial started"); | |
| DEBUG_PRINT("Voltage: "); | |
| DEBUG_PRINT(vcc.Read_Volts()); | |
| DEBUG_PRINT("Percent: "); | |
| DEBUG_PRINT(vcc.Read_Perc(vccMin, vccMax)); | |
| DEBUG_PRINTLN(" %"); | |
| /* | |
| delay(500); | |
| DEBUG_PRINT("Internal temp: "); | |
| DEBUG_PRINT(GetInternalTemp()); // Probably not calibrated. Just to print something. | |
| DEBUG_PRINTLN(" *C"); | |
| */ | |
| delay(500); // Allow time for radio if power used as reset | |
| gw.begin(NULL,NODE_ID); | |
| gw.sendSketchInfo(SKETCH_INFO, SKETCH_VERSION); | |
| gw.present(CHILD_ID_TEMP, S_TEMP); // Present sensor to controller | |
| gw.present(CHILD_ID_HUM, S_HUM); | |
| // Reed Switch | |
| pinMode(REED_BUTTON_PIN,INPUT_PULLUP); | |
| // After setting up the button, setup debouncer | |
| //debouncer.attach(REED_BUTTON_PIN); | |
| //debouncer.interval(5); | |
| // Register binary input sensor to gw (they will be created as child devices) | |
| // You can use S_DOOR, S_MOTION or S_LIGHT here depending on your usage. | |
| // If S_LIGHT is used, remember to update variable type you send in. See "msg" above. | |
| gw.present(CHILD_ID_REED, S_DOOR); | |
| DEBUG_PRINT("Node and "); DEBUG_PRINTLN("2 children presented."); | |
| raHum.clear(); | |
| } | |
| void loop() { | |
| // Process incoming messages (like config from server) | |
| gw.process(); | |
| measureCount ++; | |
| batteryReportCounter ++; | |
| bool forceTransmit = false; | |
| if (measureCount > FORCE_TRANSMIT_CYCLE) { | |
| forceTransmit = true; | |
| } | |
| sendTempHumidityMeasurements(forceTransmit); | |
| /* | |
| // Read and print internal temp | |
| float temperature0 = static_cast<float>(static_cast<int>((GetInternalTemp()+0.5) * 10.)) / 10.; | |
| DEBUG_PRINT("Internal Temp: "); DEBUG_PRINT(temperature0); DEBUG_PRINTLN(" *C"); | |
| */ | |
| // Check battery | |
| if (batteryReportCounter >= BATTERY_REPORT_CYCLE) { | |
| float batteryVolt = vcc.Read_Volts(); | |
| DEBUG_PRINT("Battery voltage: "); DEBUG_PRINT(batteryVolt); DEBUG_PRINTLN(" V"); | |
| uint8_t batteryPcnt = vcc.Read_Perc(vccMin, vccMax); //constrain(map(batteryVolt,VMIN,VMAX,0,100),0,255); | |
| DEBUG_PRINT("Battery percent: "); DEBUG_PRINT(batteryPcnt); DEBUG_PRINTLN(" %"); | |
| gw.sendBatteryLevel(batteryPcnt); | |
| batteryReportCounter = 0; | |
| } | |
| sendReedChange(); | |
| gw.sleep(REED_BUTTON_PIN-2, CHANGE, SLEEP_TIME); | |
| } | |
| void sendReedChange() { | |
| //debouncer.update(); | |
| // Get the update value | |
| //int value = debouncer.read(); | |
| int value = digitalRead(REED_BUTTON_PIN); | |
| if (value != oldValue) { | |
| // Send in the new value | |
| DEBUG_PRINT("Reed Switch #1: "); DEBUG_PRINT(value==HIGH ? 1 : 0); DEBUG_PRINTLN(""); | |
| gw.send(msgReed.set(value==HIGH ? 0 : 1)); //NO | |
| oldValue = value; | |
| } | |
| } | |
| // function for reading Vcc by reading 1.1V reference against AVcc. Based from http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/ | |
| // To calibrate reading replace 1125300L with scale_constant = internal1.1Ref * 1023 * 1000, where internal1.1Ref = 1.1 * Vcc1 (per voltmeter) / Vcc2 (per readVcc() function) | |
| /*long readVcc() { | |
| // set the reference to Vcc and the measurement to the internal 1.1V reference | |
| ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | |
| delay(2); // Wait for Vref to settle | |
| ADCSRA |= _BV(ADSC); // Start conversion | |
| while (bit_is_set(ADCSRA,ADSC)); // measuring | |
| uint8_t low = ADCL; // must read ADCL first - it then locks ADCH | |
| uint8_t high = ADCH; // unlocks both | |
| long result = (high<<8) | low; | |
| result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 | |
| return result; // Vcc in millivolts | |
| } | |
| // function for reading internal temp. From http://playground.arduino.cc/Main/InternalTemperatureSensor | |
| double GetInternalTemp(void) { // (Both double and float are 4 byte in most arduino implementation) | |
| unsigned int wADC; | |
| double t; | |
| // The internal temperature has to be used with the internal reference of 1.1V. Channel 8 can not be selected with the analogRead function yet. | |
| ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3)); // Set the internal reference and mux. | |
| ADCSRA |= _BV(ADEN); // enable the ADC | |
| delay(20); // wait for voltages to become stable. | |
| ADCSRA |= _BV(ADSC); // Start the ADC | |
| while (bit_is_set(ADCSRA,ADSC)); // Detect end-of-conversion | |
| wADC = ADCW; // Reading register "ADCW" takes care of how to read ADCL and ADCH. | |
| t = (wADC - 88.0 ) / 1.0; // The default offset is 324.31. | |
| return (t); // The returned temperature in degrees Celcius. | |
| } | |
| /********************************************* | |
| * * Sends temperature and humidity from Si7021 sensor | |
| * Parameters | |
| * - force : Forces transmission of a value (even if it's the same as previous measurement) | |
| *********************************************/ | |
| void sendTempHumidityMeasurements(bool force) { | |
| bool tx = force; | |
| si7021_env data = humiditySensor.getHumidityAndTemperature(); | |
| float temperature = data.celsiusHundredths / 100.0; | |
| DEBUG_PRINT("T: ");DEBUG_PRINTLN(temperature); | |
| float diffTemp = abs(lastTemperature - temperature); | |
| DEBUG_PRINT(F("TempDiff :"));DEBUG_PRINTLN(diffTemp); | |
| if (diffTemp > TEMP_TRANSMIT_THRESHOLD || tx) { | |
| gw.send(msgTemp.set(temperature,1)); | |
| lastTemperature = temperature; | |
| measureCount = 0; | |
| DEBUG_PRINTLN("T sent!"); | |
| } | |
| int humidity = data.humidityPercent; | |
| DEBUG_PRINT("H: ");DEBUG_PRINTLN(humidity); | |
| raHum.addValue(humidity); | |
| humidity = raHum.getAverage(); // MA sample imply reasonable fast sample frequency | |
| float diffHum = abs(lastHumidity - humidity); | |
| DEBUG_PRINT(F("HumDiff :"));DEBUG_PRINTLN(diffHum); | |
| if (diffHum > HUMI_TRANSMIT_THRESHOLD || tx) { | |
| gw.send(msgHum.set(humidity)); | |
| lastHumidity = humidity; | |
| measureCount = 0; | |
| DEBUG_PRINTLN("H sent!"); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment