Battery powered PIR and temp/humid sensor
-
True, if you wake up from pin change you haven't the exact knowledge of elapsed time (< MAX-SLEEP-TIME though).
But in most applications I doubt it would super exact temp-send-interval would matter much... It will only diff when pin change wake-up interfere.
-
@Haakon I have one of these sensor in place since about half a year and it is working well. Last battery change is about 4 month ago.
Please find the sketch below which requires some cleanup.
/* Multisensor Sketch Author: Thomas Krebs, thkrebs@gmx.de This sketch reads temperature, humidity, light and presence. It is based on the various examples sketches from SparkFun and MySensors It uses the following sensors: Light - TSL2561 Temp&Humidity - HTU21D Presence HTU21D and TLS2561 need to connect the I2C pins (SCL and SDA) to your Arduino. The pins are different on different Arduinos: SDA SCL Any Arduino "SDA" "SCL" Uno, Redboard, Pro A4 A5 Mega2560, Due 20 21 Leonardo 2 3 */ #define MY_DEBUG_VERBOSE_SIGNING //!< Enable signing related debug prints to serial monitor #define MY_SIGNING_FEATURE #define MY_SIGNING_ATSHA204 #define MY_SIGNING_REQUEST_SIGNATURES #define MY_DEBUG #define MY_NODE_ID 26 #define MY_RADIO_NRF24 #define BATT_SENSOR #include <MySensor.h> #include <TSL2561.h> #include <SparkFunHTU21D.h> #include <SPI.h> #include <Wire.h> #include <avr/power.h> #define VERSION "1.4" #define SKETCH_NAME "Multisensor A" #define TEMP_CHILD_ID 1 #define HUM_CHILD_ID 2 #define LIGHT_CHILD_ID 3 #define MOTION_CHILD_ID 4 // Uncomment the line below, to transmit battery voltage as a normal sensor value #define BATT_SENSOR 199 #define MAX_VOLTAGE 1316 #define MIN_VOLTAGE 890 // it seems that about 0.89 V the sensor stops working // How many milli seconds between each measurement #define MEASURE_INTERVAL 120000 // FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller #define FORCE_TRANSMIT_INTERVAL 30 // When MEASURE_INTERVAL is 60000 and FORCE_TRANSMIT_INTERVAL is 30, we force a transmission every 30 minutes. // Between the forced transmissions a tranmission will only occur if the measured value differs from the previous measurement // HUMI_TRANSMIT_THRESHOLD tells how much the humidity should have changed since last time it was transmitted. Likewise with // TEMP_TRANSMIT_THRESHOLD for temperature threshold. #define HUMI_TRANSMIT_THRESHOLD 0.5 #define TEMP_TRANSMIT_THRESHOLD 0.5 #define LIGHT_TRANSMIT_THRESHOLD 0.3 // relative change // Pin definitions #define LED_PIN 13 // TODO: need to check that #define BATTERY_SENSE_PIN A0 // select the input pin for the battery sense point #define MOTION_SENSOR 3 // The digital input you attached your motion sensor. (Only 2 and 3 generates interrupt!) #define INTERRUPT 1 // Usually the interrupt = pin -2 (on uno/nano anyway) // Global settings int tempMeasureCount = 0; int lightMeasureCount = 0; int sendBattery = 0; boolean isMetric = true; boolean highfreq = true; boolean motionDetected = false; int repeats = 2; // Storage of old measurements float lastTemperature = -100; float lastHumidity = -100; long lastBattery = -100; long lastLight = -5000; int lastTripped = -1; int motionTrips = 0; // count the number of cont. motion trips HTU21D myHumidity; TSL2561 myLight(TSL2561_ADDR_FLOAT); // Sensor messages MyMessage msgTemp(TEMP_CHILD_ID,V_TEMP); MyMessage msgHum(HUM_CHILD_ID,V_HUM); MyMessage msgLight(LIGHT_CHILD_ID,V_LEVEL); MyMessage msg(MOTION_CHILD_ID, V_TRIPPED); #ifdef BATT_SENSOR MyMessage msgBatt(BATT_SENSOR, V_VOLTAGE); #endif /**************************************************** * * Setup code * ****************************************************/ void setup() { pinMode(LED_PIN, OUTPUT); Serial.print(F(SKETCH_NAME)); Serial.println(VERSION); Serial.flush(); #ifdef MY_SIGNING_ATSHA204_PIN // Make sure that ATSHA204 is not floating pinMode(MY_SIGNING_ATSHA204_PIN, INPUT); digitalWrite(MY_SIGNING_ATSHA204_PIN, HIGH); #endif // use the 1.1 V internal reference analogReference(INTERNAL); // setup sensors setup_htu21d(); delay(100); setup_tls2561(); delay(500); // setup motion sensor pinMode(MOTION_SENSOR, INPUT); Serial.println(F("Setup complete...")); } void presentation() { // Send the sketch version information to the gateway and Controller sendSketchInfo(SKETCH_NAME, VERSION); // Present all sensors to controller present(TEMP_CHILD_ID, S_TEMP); present(HUM_CHILD_ID, S_HUM); // present(LIGHT_CHILD_ID,S_LIGHT_LEVEL); present(MOTION_CHILD_ID, S_MOTION); #ifdef BATT_SENSOR present(BATT_SENSOR, S_POWER); #endif isMetric = getConfig().isMetric; #ifdef MY_DEBUG Serial.print(F("isMetric: ")); Serial.println(isMetric); #endif Serial.flush(); Serial.println(F(" - Online!")); } /*********************************************** /* Setup HTU21d ***********************************************/ void setup_htu21d() { myHumidity.begin(); #ifdef MY_DEBUG Serial.println("Setup temp/humid sensor completed"); #endif } /*********************************************** /* Setup TLS2561 ***********************************************/ void setup_tls2561() { if (myLight.begin()) { Serial.println(F("Found light sensor")); } else { Serial.println(F("Light Sensor not found - cont. anyway")); } myLight.setGain(TSL2561_GAIN_0X); // set 16x gain (for dim situations) // Changing the integration time gives you a longer time over which to sense light // longer timelines are slower, but are good in very low light situtations! //tsl.setTiming(TSL2561_INTEGRATIONTIME_13MS); // shortest integration time (bright light) myLight.setTiming(TSL2561_INTEGRATIONTIME_101MS); // medium integration time (medium light) //tsl.setTiming(TSL2561_INTEGRATIONTIME_402MS); // longest integration time (dim light) } /*********************************************** * * Main loop function * ***********************************************/ void loop() { tempMeasureCount++; lightMeasureCount++; sendBattery++; bool forceTransmit = false; if (motionDetected) { sendMotion(false); // do not force transmission unless motion status has changed motionDetected = false; } // do not enter into sensor data gathering on each motion tripped if ((!motionDetected) || (motionTrips > 3)) { motionTrips = 0; // avoid starvation of temp measure in case we have a lot of motion // I do the battery check at the beginning if (sendBattery > 60) { sendBattLevel(forceTransmit); // Not needed to send battery info that often sendBattery = 0; } if ((lightMeasureCount > FORCE_TRANSMIT_INTERVAL) || (tempMeasureCount > FORCE_TRANSMIT_INTERVAL) ) { // force a transmission forceTransmit = true; tempMeasureCount = 0; lightMeasureCount = 0; } // Get & send sensor data wait(200); sendTempHumidityMeasurement(forceTransmit); wait(200); sendLightLevelMeasurement(forceTransmit); wait(200); sendMotion(forceTransmit); } wait(100); // I don't know whether that is really required; however I have the impression that shutting down the radio leads to // problems in the communication when using signatures Serial.println("going to sleep"); if (sleep(INTERRUPT,RISING, MEASURE_INTERVAL)) { motionDetected = true; motionTrips++; } Serial.print("Motion detected="); Serial.println(motionDetected); } /********************************************* * * Sends state of motion sensor * * Parameters * - force : Forces transmission of a value (even if it's the same as previous measurement) * *********************************************/ void sendMotion(bool force) { bool tx = force; // Read digital motion value bool tripped = digitalRead(MOTION_SENSOR) == HIGH; Serial.print(F("Tripped: ")); Serial.println(tripped); if (lastTripped != tripped) tx = true; if (tx) { resend(msg.set(tripped?"1":"0"),repeats); // Send tripped value to gw lastTripped = tripped; } } /********************************************* * * Sends temperature and humidity from HTU21D sensor * * Parameters * - force : Forces transmission of a value (even if it's the same as previous measurement) * *********************************************/ void sendTempHumidityMeasurement(bool force) { bool tx = force; float hum = myHumidity.readHumidity(); float temp = myHumidity.readTemperature(); Serial.print(F("lastTemperature: ")); Serial.println(lastTemperature); Serial.print(F("lastHumidity: ")); Serial.println(lastHumidity); float diffTemp = abs(lastTemperature - temp); float diffHum = abs(lastHumidity - hum); #ifdef MY_DEBUG Serial.print(F("TempDiff :"));Serial.println(diffTemp); Serial.print(F("HumDiff :"));Serial.println(diffHum); #endif if (isnan(diffHum)) tx = true; if (diffTemp > TEMP_TRANSMIT_THRESHOLD) tx = true; if (diffHum >= HUMI_TRANSMIT_THRESHOLD) tx = true; if (tx) { tempMeasureCount = 0; resend(msgTemp.setSensor(TEMP_CHILD_ID).set(temp,1),repeats); wait(20); resend(msgHum.setSensor(HUM_CHILD_ID).set(hum,1),repeats); lastTemperature = temp; lastHumidity = hum; } } /********************************************* * * Sends light level from TLS6512 sensor * * Parameters * - force : Forces transmission of a value (even if it's the same as previous measurement) * *********************************************/ void sendLightLevelMeasurement(bool force) { bool tx = force; uint32_t lum = myLight.getFullLuminosity(); uint16_t ir, full; ir = lum >> 16; full = lum & 0xFFFF; Serial.print(F("IR: ")); Serial.print(ir); Serial.print(F("\t\t")); Serial.print(F("Full: ")); Serial.print(full); Serial.print(F("\t")); Serial.print(F("Visible: ")); Serial.print(full - ir); Serial.print(F("\t")); double lux = myLight.calculateLux(full, ir); Serial.print(F("Lux: ")); Serial.println(lux); float diffLux = abs(lastLight - lux); #ifdef MY_DEBUG Serial.print(F("Lux difference since last measurement: ")); Serial.println((float)diffLux/abs(lastLight)); #endif if (isnan(diffLux)) tx = true; if (diffLux/abs(lastLight) >= LIGHT_TRANSMIT_THRESHOLD) tx = true; if (tx) { lightMeasureCount = 0; resend(msgLight.setSensor(LIGHT_CHILD_ID).set(lux,1),repeats); lastLight = lux; } } /********************************************* * Prints error on I2C comm bus *********************************************/ void printError(byte error) // If there's an I2C error, this function will // print out an explanation. { Serial.print(F("I2C error: ")); Serial.print(error,DEC); Serial.print(F(", ")); switch(error) { case 0: Serial.println(F("success")); break; case 1: Serial.println(F("data too long for transmit buffer")); break; case 2: Serial.println(F("received NACK on address (disconnected?)")); break; case 3: Serial.println(F("received NACK on data")); break; case 4: Serial.println(F("other error")); break; default: Serial.println(F("unknown error")); } } /******************************************** * * Sends battery information (battery percentage) * * Parameters * - force : Forces transmission of a value * *******************************************/ void sendBattLevel(bool force) { if (force) lastBattery = -1; long batteryV = analogRead(BATTERY_SENSE_PIN); for (int i = 1; i<5; i++) { long newSample = analogRead(BATTERY_SENSE_PIN); //readVcc(); batteryV -= batteryV / (i+1); batteryV += newSample / (i+1); } // 10M, 2,86M divider across battery and using internal ADC ref of 1.1V // Sense point is bypassed with 0.1 uF cap to reduce noise at that point // ((10+4,7)/4,7)*1.1 = 3.4404255 // 3.4404255/1023 = Volts per bit = 0.003630748 long vcc = batteryV * 3.3630748; if (vcc != lastBattery) { lastBattery = vcc; #ifdef BATT_SENSOR resend(msgBatt.set(vcc),repeats); #endif // Calculate on the fully charged cell. Since I have a step-up in place I go as low as possible no offset for minimum sendBatteryLevel( ((vcc-MIN_VOLTAGE)*10.0)/((MAX_VOLTAGE-MIN_VOLTAGE)*10.0) *100.0); } } /******************************************** * * Send message, resend on error * * Parameters * - msg : message to send * - repeats: number of repetitions * *******************************************/ void resend(MyMessage &msg, int repeats) { int repeat = 0; int repeatdelay = 0; boolean sendOK = false; while ((sendOK == false) and (repeat < repeats)) { if (send(msg)) { sendOK = true; } else { sendOK = false; Serial.print(F("Send ERROR ")); Serial.println(repeat); repeatdelay += random(50,200); } repeat++; delay(repeatdelay); } } /******************************************* * * Internal battery ADC measuring * *******************************************/ long readVcc() { // Read 1.1V reference against AVcc // set the reference to Vcc and the measurement to the internal 1.1V reference #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) ADMUX = _BV(MUX5) | _BV(MUX0); #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADcdMUX = _BV(MUX3) | _BV(MUX2); #else ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #endif 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 } -
@Haakon I have one of these sensor in place since about half a year and it is working well. Last battery change is about 4 month ago.
Please find the sketch below which requires some cleanup.
/* Multisensor Sketch Author: Thomas Krebs, thkrebs@gmx.de This sketch reads temperature, humidity, light and presence. It is based on the various examples sketches from SparkFun and MySensors It uses the following sensors: Light - TSL2561 Temp&Humidity - HTU21D Presence HTU21D and TLS2561 need to connect the I2C pins (SCL and SDA) to your Arduino. The pins are different on different Arduinos: SDA SCL Any Arduino "SDA" "SCL" Uno, Redboard, Pro A4 A5 Mega2560, Due 20 21 Leonardo 2 3 */ #define MY_DEBUG_VERBOSE_SIGNING //!< Enable signing related debug prints to serial monitor #define MY_SIGNING_FEATURE #define MY_SIGNING_ATSHA204 #define MY_SIGNING_REQUEST_SIGNATURES #define MY_DEBUG #define MY_NODE_ID 26 #define MY_RADIO_NRF24 #define BATT_SENSOR #include <MySensor.h> #include <TSL2561.h> #include <SparkFunHTU21D.h> #include <SPI.h> #include <Wire.h> #include <avr/power.h> #define VERSION "1.4" #define SKETCH_NAME "Multisensor A" #define TEMP_CHILD_ID 1 #define HUM_CHILD_ID 2 #define LIGHT_CHILD_ID 3 #define MOTION_CHILD_ID 4 // Uncomment the line below, to transmit battery voltage as a normal sensor value #define BATT_SENSOR 199 #define MAX_VOLTAGE 1316 #define MIN_VOLTAGE 890 // it seems that about 0.89 V the sensor stops working // How many milli seconds between each measurement #define MEASURE_INTERVAL 120000 // FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller #define FORCE_TRANSMIT_INTERVAL 30 // When MEASURE_INTERVAL is 60000 and FORCE_TRANSMIT_INTERVAL is 30, we force a transmission every 30 minutes. // Between the forced transmissions a tranmission will only occur if the measured value differs from the previous measurement // HUMI_TRANSMIT_THRESHOLD tells how much the humidity should have changed since last time it was transmitted. Likewise with // TEMP_TRANSMIT_THRESHOLD for temperature threshold. #define HUMI_TRANSMIT_THRESHOLD 0.5 #define TEMP_TRANSMIT_THRESHOLD 0.5 #define LIGHT_TRANSMIT_THRESHOLD 0.3 // relative change // Pin definitions #define LED_PIN 13 // TODO: need to check that #define BATTERY_SENSE_PIN A0 // select the input pin for the battery sense point #define MOTION_SENSOR 3 // The digital input you attached your motion sensor. (Only 2 and 3 generates interrupt!) #define INTERRUPT 1 // Usually the interrupt = pin -2 (on uno/nano anyway) // Global settings int tempMeasureCount = 0; int lightMeasureCount = 0; int sendBattery = 0; boolean isMetric = true; boolean highfreq = true; boolean motionDetected = false; int repeats = 2; // Storage of old measurements float lastTemperature = -100; float lastHumidity = -100; long lastBattery = -100; long lastLight = -5000; int lastTripped = -1; int motionTrips = 0; // count the number of cont. motion trips HTU21D myHumidity; TSL2561 myLight(TSL2561_ADDR_FLOAT); // Sensor messages MyMessage msgTemp(TEMP_CHILD_ID,V_TEMP); MyMessage msgHum(HUM_CHILD_ID,V_HUM); MyMessage msgLight(LIGHT_CHILD_ID,V_LEVEL); MyMessage msg(MOTION_CHILD_ID, V_TRIPPED); #ifdef BATT_SENSOR MyMessage msgBatt(BATT_SENSOR, V_VOLTAGE); #endif /**************************************************** * * Setup code * ****************************************************/ void setup() { pinMode(LED_PIN, OUTPUT); Serial.print(F(SKETCH_NAME)); Serial.println(VERSION); Serial.flush(); #ifdef MY_SIGNING_ATSHA204_PIN // Make sure that ATSHA204 is not floating pinMode(MY_SIGNING_ATSHA204_PIN, INPUT); digitalWrite(MY_SIGNING_ATSHA204_PIN, HIGH); #endif // use the 1.1 V internal reference analogReference(INTERNAL); // setup sensors setup_htu21d(); delay(100); setup_tls2561(); delay(500); // setup motion sensor pinMode(MOTION_SENSOR, INPUT); Serial.println(F("Setup complete...")); } void presentation() { // Send the sketch version information to the gateway and Controller sendSketchInfo(SKETCH_NAME, VERSION); // Present all sensors to controller present(TEMP_CHILD_ID, S_TEMP); present(HUM_CHILD_ID, S_HUM); // present(LIGHT_CHILD_ID,S_LIGHT_LEVEL); present(MOTION_CHILD_ID, S_MOTION); #ifdef BATT_SENSOR present(BATT_SENSOR, S_POWER); #endif isMetric = getConfig().isMetric; #ifdef MY_DEBUG Serial.print(F("isMetric: ")); Serial.println(isMetric); #endif Serial.flush(); Serial.println(F(" - Online!")); } /*********************************************** /* Setup HTU21d ***********************************************/ void setup_htu21d() { myHumidity.begin(); #ifdef MY_DEBUG Serial.println("Setup temp/humid sensor completed"); #endif } /*********************************************** /* Setup TLS2561 ***********************************************/ void setup_tls2561() { if (myLight.begin()) { Serial.println(F("Found light sensor")); } else { Serial.println(F("Light Sensor not found - cont. anyway")); } myLight.setGain(TSL2561_GAIN_0X); // set 16x gain (for dim situations) // Changing the integration time gives you a longer time over which to sense light // longer timelines are slower, but are good in very low light situtations! //tsl.setTiming(TSL2561_INTEGRATIONTIME_13MS); // shortest integration time (bright light) myLight.setTiming(TSL2561_INTEGRATIONTIME_101MS); // medium integration time (medium light) //tsl.setTiming(TSL2561_INTEGRATIONTIME_402MS); // longest integration time (dim light) } /*********************************************** * * Main loop function * ***********************************************/ void loop() { tempMeasureCount++; lightMeasureCount++; sendBattery++; bool forceTransmit = false; if (motionDetected) { sendMotion(false); // do not force transmission unless motion status has changed motionDetected = false; } // do not enter into sensor data gathering on each motion tripped if ((!motionDetected) || (motionTrips > 3)) { motionTrips = 0; // avoid starvation of temp measure in case we have a lot of motion // I do the battery check at the beginning if (sendBattery > 60) { sendBattLevel(forceTransmit); // Not needed to send battery info that often sendBattery = 0; } if ((lightMeasureCount > FORCE_TRANSMIT_INTERVAL) || (tempMeasureCount > FORCE_TRANSMIT_INTERVAL) ) { // force a transmission forceTransmit = true; tempMeasureCount = 0; lightMeasureCount = 0; } // Get & send sensor data wait(200); sendTempHumidityMeasurement(forceTransmit); wait(200); sendLightLevelMeasurement(forceTransmit); wait(200); sendMotion(forceTransmit); } wait(100); // I don't know whether that is really required; however I have the impression that shutting down the radio leads to // problems in the communication when using signatures Serial.println("going to sleep"); if (sleep(INTERRUPT,RISING, MEASURE_INTERVAL)) { motionDetected = true; motionTrips++; } Serial.print("Motion detected="); Serial.println(motionDetected); } /********************************************* * * Sends state of motion sensor * * Parameters * - force : Forces transmission of a value (even if it's the same as previous measurement) * *********************************************/ void sendMotion(bool force) { bool tx = force; // Read digital motion value bool tripped = digitalRead(MOTION_SENSOR) == HIGH; Serial.print(F("Tripped: ")); Serial.println(tripped); if (lastTripped != tripped) tx = true; if (tx) { resend(msg.set(tripped?"1":"0"),repeats); // Send tripped value to gw lastTripped = tripped; } } /********************************************* * * Sends temperature and humidity from HTU21D sensor * * Parameters * - force : Forces transmission of a value (even if it's the same as previous measurement) * *********************************************/ void sendTempHumidityMeasurement(bool force) { bool tx = force; float hum = myHumidity.readHumidity(); float temp = myHumidity.readTemperature(); Serial.print(F("lastTemperature: ")); Serial.println(lastTemperature); Serial.print(F("lastHumidity: ")); Serial.println(lastHumidity); float diffTemp = abs(lastTemperature - temp); float diffHum = abs(lastHumidity - hum); #ifdef MY_DEBUG Serial.print(F("TempDiff :"));Serial.println(diffTemp); Serial.print(F("HumDiff :"));Serial.println(diffHum); #endif if (isnan(diffHum)) tx = true; if (diffTemp > TEMP_TRANSMIT_THRESHOLD) tx = true; if (diffHum >= HUMI_TRANSMIT_THRESHOLD) tx = true; if (tx) { tempMeasureCount = 0; resend(msgTemp.setSensor(TEMP_CHILD_ID).set(temp,1),repeats); wait(20); resend(msgHum.setSensor(HUM_CHILD_ID).set(hum,1),repeats); lastTemperature = temp; lastHumidity = hum; } } /********************************************* * * Sends light level from TLS6512 sensor * * Parameters * - force : Forces transmission of a value (even if it's the same as previous measurement) * *********************************************/ void sendLightLevelMeasurement(bool force) { bool tx = force; uint32_t lum = myLight.getFullLuminosity(); uint16_t ir, full; ir = lum >> 16; full = lum & 0xFFFF; Serial.print(F("IR: ")); Serial.print(ir); Serial.print(F("\t\t")); Serial.print(F("Full: ")); Serial.print(full); Serial.print(F("\t")); Serial.print(F("Visible: ")); Serial.print(full - ir); Serial.print(F("\t")); double lux = myLight.calculateLux(full, ir); Serial.print(F("Lux: ")); Serial.println(lux); float diffLux = abs(lastLight - lux); #ifdef MY_DEBUG Serial.print(F("Lux difference since last measurement: ")); Serial.println((float)diffLux/abs(lastLight)); #endif if (isnan(diffLux)) tx = true; if (diffLux/abs(lastLight) >= LIGHT_TRANSMIT_THRESHOLD) tx = true; if (tx) { lightMeasureCount = 0; resend(msgLight.setSensor(LIGHT_CHILD_ID).set(lux,1),repeats); lastLight = lux; } } /********************************************* * Prints error on I2C comm bus *********************************************/ void printError(byte error) // If there's an I2C error, this function will // print out an explanation. { Serial.print(F("I2C error: ")); Serial.print(error,DEC); Serial.print(F(", ")); switch(error) { case 0: Serial.println(F("success")); break; case 1: Serial.println(F("data too long for transmit buffer")); break; case 2: Serial.println(F("received NACK on address (disconnected?)")); break; case 3: Serial.println(F("received NACK on data")); break; case 4: Serial.println(F("other error")); break; default: Serial.println(F("unknown error")); } } /******************************************** * * Sends battery information (battery percentage) * * Parameters * - force : Forces transmission of a value * *******************************************/ void sendBattLevel(bool force) { if (force) lastBattery = -1; long batteryV = analogRead(BATTERY_SENSE_PIN); for (int i = 1; i<5; i++) { long newSample = analogRead(BATTERY_SENSE_PIN); //readVcc(); batteryV -= batteryV / (i+1); batteryV += newSample / (i+1); } // 10M, 2,86M divider across battery and using internal ADC ref of 1.1V // Sense point is bypassed with 0.1 uF cap to reduce noise at that point // ((10+4,7)/4,7)*1.1 = 3.4404255 // 3.4404255/1023 = Volts per bit = 0.003630748 long vcc = batteryV * 3.3630748; if (vcc != lastBattery) { lastBattery = vcc; #ifdef BATT_SENSOR resend(msgBatt.set(vcc),repeats); #endif // Calculate on the fully charged cell. Since I have a step-up in place I go as low as possible no offset for minimum sendBatteryLevel( ((vcc-MIN_VOLTAGE)*10.0)/((MAX_VOLTAGE-MIN_VOLTAGE)*10.0) *100.0); } } /******************************************** * * Send message, resend on error * * Parameters * - msg : message to send * - repeats: number of repetitions * *******************************************/ void resend(MyMessage &msg, int repeats) { int repeat = 0; int repeatdelay = 0; boolean sendOK = false; while ((sendOK == false) and (repeat < repeats)) { if (send(msg)) { sendOK = true; } else { sendOK = false; Serial.print(F("Send ERROR ")); Serial.println(repeat); repeatdelay += random(50,200); } repeat++; delay(repeatdelay); } } /******************************************* * * Internal battery ADC measuring * *******************************************/ long readVcc() { // Read 1.1V reference against AVcc // set the reference to Vcc and the measurement to the internal 1.1V reference #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) ADMUX = _BV(MUX5) | _BV(MUX0); #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADcdMUX = _BV(MUX3) | _BV(MUX2); #else ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #endif 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 } -
@Haakon Regarding the PIRs: There are a couple of postings in the Internet or I think even in this forum. For example, have a look here: http://randomnerdtutorials.com/modifying-cheap-pir-motion-sensor-to-work-at-3-3v/
@tomkxy How did you power it though? I wanted to use a battery (or several ones) that might fall under 3.3V when used. So I decided to use a step-up converter but that seems to introduce too much noise, so I get false positives from the pir. From a stable 3.3V source it worked just fine.
-
@LastSamurai I powered it through 3.3v step up with one AA battery. I cannot confirm that I get false positives.
-
@LastSamurai I powered it through 3.3v step up with one AA battery. I cannot confirm that I get false positives.
What range on the PIR do you get on 3.3 V?
-
@LastSamurai I powered it through 3.3v step up with one AA battery. I cannot confirm that I get false positives.
@tomkxy said:
@LastSamurai I powered it through 3.3v step up with one AA battery. I cannot confirm that I get false positives.
Nice, what PIR and what step up did you use? Hopefully I can get the same ones too ;)
-
Hi @tomkxy
I'm going to add one of these sensors myself, looks like you've done the hard work...
Could I ask what board you are using, perhaps a simple schematic too if you find a moment? I have a bunch of Nano's, some light sensors (BH1750) and temperature sensors (DS18B20's) - I presume I can swap over the code as required. Thankfully I also have a number of those exact step ups!
-
@Mark-Swift I used a ProMini 3.3v. Unfortunately, I have no schematic. Since I used breakout boards anyway this is not a big deal. You connect those boards to your power, ground and a digital pin or on SCA, SCL pins. I don't know what the power consumption of the Nano's is. So that is something you have to try out.
-
@Mark-Swift I used a ProMini 3.3v. Unfortunately, I have no schematic. Since I used breakout boards anyway this is not a big deal. You connect those boards to your power, ground and a digital pin or on SCA, SCL pins. I don't know what the power consumption of the Nano's is. So that is something you have to try out.