Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
rvendrameR

rvendrame

@rvendrame
Hero Member
About
Posts
353
Topics
5
Shares
0
Groups
1
Followers
0
Following
4

Posts

Recent Best Controversial

  • Combining a motion sensor with an led on one node
    rvendrameR rvendrame

    @TonicCorvid basically you just replace this line:

    sleep(digitalPinToInterrupt(MOTION_DIGITAL_INPUT_SENSOR), CHANGE, SLEEP_TIME);
    

    by this:

    wait( SLEEP_TIME );
    

    But as pointed by @rejoe2 , this will drain the battery quite fast, as the node will be always on-line. Usually for actuator nodes (such as lights), a power supply is used, instead of batteries.

    Development

  • Combining a motion sensor with an led on one node
    rvendrameR rvendrame

    @TonicCorvid ,

    issue 1: The light node cannot receive messages from home assistant while it is sleeping. You may start by replacing the sleep command by a wait:

    wait( SLEEP_TIME );
    

    issue 2: Usually Home Assistant needs the light send its current status, in order to 'activate' it. Try adding a line in the end of presentation part:

    #ifdef ID_S_LIGHT
      Serial.println("  S_LIGHT");
      present(ID_S_LIGHT, S_LIGHT, "Kitchen Night Light");
      wait(SHORT_WAIT);
      send(msg_S_LIGHT.set(isLightOn));   <<<<<<<<<<<<<<
    #endif
    
    Development

  • Water level measurement - Ultrasonics V Pressure
    rvendrameR rvendrame

    @zboblamont thanks a lot! I will try it and report back here.

    Hardware

  • Water level measurement - Ultrasonics V Pressure
    rvendrameR rvendrame

    @zboblamont may I ask you what pressure sensor have you choosen? My ultrassonic sensor suffers from the same plague as yours...

    Hardware

  • JSN-SR04T (distance sensor) Reliability Issue Fix?
    rvendrameR rvendrame

    @Thomas-Weeks I'm looking for alternatives, as I started with JSN04T. Scope is to measure house's water tank (2000 litres). The sensor is fixed at a hole in the tank cover (on top).

    The tank stays at roof. Once sun in at its peak, a lot of vapor and condesantion appears in the tank, and the sensor face gets completely covered by water drops. Both JSN04T and VL5310X then start to give very out-of-range readings. (and this happens almost every day, for multiple hours).

    Troubleshooting

  • JSN-SR04T (distance sensor) Reliability Issue Fix?
    rvendrameR rvendrame

    @Thomas-Weeks , in your scenario do you have to deal with condensation (water vapor moisture) on sensor head? I replaced my ultrassonic SN04T by a time-of-flight VL5310X , but still getting many erratic readings when drips form on sensor face...

    Troubleshooting

  • What I must buy in order to measure mAh please
    rvendrameR rvendrame

    @DenisJ I built one of these some years ago and I'm still happy with

    https://www.openhardware.io/view/380/Micro-nano-ampere-meter-double

    It covers the range you mentioned at least. Hope it helps.

    Hardware

  • RGB Light: Custom Effects
    rvendrameR rvendrame

    @electrik , thanks for the directions. Yes the S_CUSTOM does show up in HA --- But how to change its value there? I can set different values in dev tools UI, but that is known to be temporary (it lasts only until next refresh from integration), and changing it there does not trigger a V_VAR1 message from HA back to node...

    Home Assistant

  • RGB Light: Custom Effects
    rvendrameR rvendrame

    Anyone figured out how to trigger an update + sending of V_VAR1 / V_VAR2 from home assistant to a node?

    My goal is to trigger custom effects in a mysensor-RGB node.

    (Yes, I know my sketch could present switches to allow triggering of the effects but I wanted to learn more how HA mySensor integration works and maybe couple with HA's existing 'effect_list' attribute for RGB lights).

    Home Assistant

  • MH-Z14A CO2 senso
    rvendrameR rvendrame

    @viti this forum is in English, please use that. For CO2 sensor you might starting looking at https://www.mysensors.org/build/gas

    Hardware

  • Modifying A0 value to Percentage
    rvendrameR rvendrame

    @mrhutchinsonmn said in Modifying A0 value to Percentage:

    @rvendrame That worked! I did need to change "float moisture_percentage" to init "moisture_percentage" to get passed the "Call of overloaded function is ambiguous" error. Not sure if that is the correct approach but I was able to compile and upload. Not sure how I missed the send msg but I did. Thanks again!

    I'm glad it worked! And right, the code I provided was to work with integers.

    if you want to keep using float (and have decimals places), you have to add the number of decimal places in send function ( I put 2 decimals in this example):

    send(msg.set( moisture_percentage , 2  ));
    
    General Discussion

  • Modifying A0 value to Percentage
    rvendrameR rvendrame

    @mrhutchinsonmn I think you just need to replace this line in the first sketch:

    send(msg.set(sensorValue));
    

    By this:

    float moisture_percentage;
    moisture_percentage = ( 100 - ( (sensorValue/1023.00) * 100 ) );
    send(msg.set( moisture_percentage ));
    

    I don't use HA so I don't know if something needs to be changed in HA side...

    General Discussion

  • BME280/BMP280 high consumption when sleeping
    rvendrameR rvendrame

    @bbastos , welcome to mySensors. Try to add these lines before the sleep():

    digitalWrite( A4 , LOW ); 
    digitalWrite( A5 , LOW ); 
    

    Stills unclear why, but it worked for me at least.

    Reference: https://forum.mysensors.org/post/99876

    NodeManager

  • sending an image without wifi / envoi d'une image hors wifi
    rvendrameR rvendrame

    @rejoe2 if you have to run a wire to the place where the camera will be installed, you could use CAT-6 regular ethernet cable. That would carry TCP/IP signal and could also carry power (via POE). And you could use any ordinary IP-camera...

    Hardware

  • Pool Sensor (analog)
    rvendrameR rvendrame

    @netbus I use the waterproof version of DS18B20 in my pool sensor and it works perfectly, 3 years now and counting ;-)

    Hardware

  • MyS not working on solar sensor board
    rvendrameR rvendrame

    @ramwal I'm glad you got it working!

    Troubleshooting

  • MyS not working on solar sensor board
    rvendrameR rvendrame

    @ramwal

    f6eeb556-f957-4f82-95d2-c8be09b606d3-image.png

    These boards use a different CE and CS pins in Arduino. Try to add this BEFORE the #include <MySensors.h>:

    #define MY_RF24_CE_PIN 7 // Ceech Arista board 
    #define MY_RF24_CS_PIN 8 // Ceech Arista board
    // Includes -------------------------------------------
    #include <MySensors.h> 
    
    Troubleshooting

  • TV on/off monitor using TV USB port
    rvendrameR rvendrame

    Just brainstorming: a Door/Window sensor with 2xAA batteries may last ~2 years, if you remove the led and regulator. You just need to connect the USB - to GND and USB + to D3 via a diode.

    Another option is to replace the 2xAA by a small lithium battery, with one of these cheap TP4056 charger boards, so the USB from TV will keep the battery charged. You just need to connect +VCC (from the USB connector side) to D3 via a diode.

    https://www.aliexpress.com/w/wholesale-board-tp4056.html
    https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20200427084513&SearchText=small+lithium

    Hardware

  • Ceech Board MOSFET Pin DIGITALWRITE Problem
    rvendrameR rvendrame

    @paqor I recently converted the sketch to 2.x . Here it goes:

    /**
     * The MySensors Arduino library handles the wireless radio link and protocol
     * between your home built sensors/actuators and HA controller of choice.
     * The sensors forms a self healing radio network with optional repeaters. Each
     * repeater and gateway builds a routing tables in EEPROM which keeps track of the
     * network topology allowing messages to be routed to nodes.
     *
     * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
     * Copyright (C) 2013-2015 Sensnology AB
     * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
     *
     * Documentation: http://www.mysensors.org
     * Support Forum: http://forum.mysensors.org
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     *******************************
     *
     * REVISION HISTORY
     * Version 1.0 - Initial Version by rvendrame
     * 
     ******************************
     * DESCRIPTION
     * Floating Swiming pool sensor based on ceech's arista board 
     *   (see https://www.tindie.com/products/ceech/astri-arista/ ) 
     *   Solar-powered (+Li-ion 18650 battery backup)
     * PH Measurement via A3 pin,  using DFrobot SEN0161 PH sensor 
     *    (see https://www.dfrobot.com/wiki/index.php/PH_meter(SKU:_SEN0161)
     * ORP Measurement via A1 pin,  using Phidgets 1130_0 board + 3556_0 Electrode 
     *    (see http://www.phidgets.com/products.php?product_id=1130)
     *    (see http://www.phidgets.com/products.php?product_id=3556)
     * Temp sensor via D4 pin,  using DS18B20 sensor
     *    (see https://create.arduino.cc/projecthub/TheGadgetBoy/ds18b20-digital-temperature-sensor-and-arduino-9cc806 ) 
     *    
     *    Revisions: 
     *    1.0  ( ??? 2017 ) - Initial version 
     *    1.1  ( Jan 2020 ) - MySensors 2.x port 
     */
    
    // Enable debug prints to serial monitor
    //#define MY_DEBUG
    
    // CEECH BOARD
    #define CEECH 
    
    // Define a static node address, AUTO or 1-255 fixed
    #define MY_NODE_ID AUTO
    #define MY_PARENT_NODE_ID AUTO
    
    // Enable and select radio type attached
    #define MY_RADIO_RF24  // MY_RADIO_RFM69
    
    // MySensors 
    #define SN "myPoolWater"
    #define SV "1.2"
    #ifdef CEECH 
    #define MY_RF24_CE_PIN 7 // Ceech Arista board 
    #define MY_RF24_CS_PIN 8 // Ceech Arista board
    #endif
    
    // Includes -------------------------------------------
    #include <MySensors.h> 
    #include <SPI.h>
    #include <OneWire.h>
    #include <DallasTemperature.h>
    
    // External IO Pins 
    #define PH_PIN           A3  // pH Sensor dfrobot SKU SEN0161
    #define ORP_PIN          A1  // ORP Sensor phidgets ASR2801 (3556_0) + 1103_0 
    #define ONE_WIRE_BUS     5   // One wire bus
    
    // Runtime constants
    #define day 86400000L // 86400000 milliseconds in a day
    #define hour 3600000L // 3600000 milliseconds in an hour
    #define minute 60000L // 60000 milliseconds in a minute
    #define second  1000L // 1000 milliseconds in a second
    
    // Ceech-Arista Internal connections 
    #define  current A6  // Charging current from Solar Panel 
    #define  cell    A2  // Voltage at Solar Panel 
    #define  lipo    A0  // Voltage at Battery 
    #define  CHRG    A7  // Charge indicator ( 0 means 'charging' ) 
    #define  POWER   4   // MOSFET driver on 5V Step up (to power the sensors) 
    #define  R1      47000.0  // resistance of R1
    #define  R2      10000.0  // resistance of R2
    
    // mySensors objects
    MyMessage ph_msg( 2, V_PH ),
              orp_msg( 3, V_ORP ),
              temp_msg( 1, V_TEMP ),
              bat_msg( 199 , V_VOLTAGE ),
              var1_msg( 0 , V_VAR1 ), 
              var2_msg( 0 , V_VAR2 ),
              var3_msg( 0 , V_VAR3 );  
    
    // Setup a oneWire instance to communicate with any OneWire devices 
    // (not just Maxim/Dallas temperature ICs)
    OneWire oneWire(ONE_WIRE_BUS);
     
    // Pass our oneWire reference to Dallas Temperature.
    DallasTemperature dallas(&oneWire);
    
    // Misc 
    #define pHOffset         0.00  // pH deviation compensate
    #define samplingInterval 20    // in miliseconds 
    #define arrayLenth       40    // times of collection
    
    // PH / ORP / Temp  Reading
    static unsigned long samplingTime = millis();
    static float temp, ph, orp, voltage;
    static float aux, dif, old_ph=999, old_orp=999, old_temp=999;
    int   battery, counter = -1, 
          old_bat=999, old_volt=9999; 
    
    
    int readings[arrayLenth];   //Store the average value of the sensor feedback
    int arrayIndex = 0;
    
    // Misc  
    float vout = 0.0;
    float vin = 0.0;
    int value = 0;
    
    //// SETUP
    void setup() {
    
      Serial.begin( MY_BAUD_RATE );
      Serial.println(F("Init..."));
    
      // IO PINS
      pinMode( POWER   , OUTPUT );
      pinMode( PH_PIN  , INPUT );
      pinMode( ORP_PIN , INPUT ); 
    
    }
    
    //// PRESENTATION 
    void presentation() { 
      
      sendSketchInfo(SN, SV);
    
      present( 1, S_TEMP );          // Temperature
      present( 2, S_WATER_QUALITY ); // PH
      present( 3, S_WATER_QUALITY ); // ORP
    
    }
    //// LOOP
    void loop() {
    
      // Force a refresh on each hour...
      if ( ++counter == 5 ) {
        old_ph = old_orp = old_temp = -999;
        old_bat = old_volt = -999;
        counter = 0;
      }
    
      // Internal board/battery status 
      digitalWrite( POWER , true );
      Serial.println("5V Power ON - Wait 5s");
      wait(5000); 
    
      float napetost = readVcc();
    
      Serial.println("*Internal:"); 
      
      value = analogRead(cell);
      vout = (value * napetost) / 1024.0;
      vin = vout / (R2 / (R1 + R2));
      if (vin < 0.09) vin = 0.0;
      
      float tok = ((analogRead(current) * napetost / 1024 ) * 250) / 3.3; // convert the ADC value to miliamps
      float baterija = ( analogRead(lipo) * napetost / 1024 ) * 2; // measuring battery voltage
      int polnjenje = analogRead(CHRG);
    
      Serial.print("Vcc = ");
      Serial.print(napetost);
      Serial.println("V");
      //delay(400);
      Serial.print("Charge current = ");
      Serial.print(tok);
      Serial.println("mA");
      //delay(400);
      Serial.print("Solar cell voltage = ");
      Serial.print(vin);
      Serial.println("V");
      //delay(400);
      Serial.print("Battery voltage = ");
      Serial.print(baterija);
      Serial.print("V  ");
      aux = constrain( map( baterija*1000 , 2200 , 4000 , 0 , 100 ) , 0 , 100 );
      Serial.print( aux , 0  );
      Serial.println("%");
      dif = aux - old_bat;
      if ( abs( dif ) > 0 ) {
        old_bat = aux;
        send( bat_msg.set(baterija,2) );
        sendBatteryLevel( aux) ;
        send ( var3_msg.set(vin,2) ); 
      }
      //delay(400);
      Serial.print("CHRG = ");
      Serial.println(polnjenje);
    
      Serial.println("*External:"); 
      
      //////// Temp Reading
      dallas.begin();  // Start up the library
      dallas.requestTemperatures();
      temp = dallas.getTempCByIndex(0); 
      Serial.print( "Temperature: "); 
      Serial.println( temp , 2 ); 
      dif = old_temp - temp;
      if ( abs( dif ) > 0.01 ) {
         old_temp = temp;
         send( temp_msg.set( temp , 2 ) ) ;
      }
      
      //////// PH Reading
      arrayIndex = 0;
      while ( arrayIndex < arrayLenth )
        if (millis() - samplingTime > samplingInterval)
        {
          readings[arrayIndex++] = analogRead(PH_PIN);
          samplingTime = millis();
        }
      
      voltage = avergearray( readings, arrayLenth ) * 3.30 / 1024.0;
      ph = 3.5 * ( voltage + pHOffset );
    
      Serial.print("PH Probe voltage:");
      Serial.print(voltage, 4);
      Serial.print("    pH value: ");
      Serial.println( ph , 2);
      dif = old_ph - ph;
      if ( abs( dif ) > 0.005 ) {
         old_ph = ph;
         send( ph_msg.set( ph , 2 ) ) ;
         send( var1_msg.set( voltage, 4) ); 
      }
    
    
      /////////// ORP 
      arrayIndex = 0;
      while ( arrayIndex < arrayLenth )
        if (millis() - samplingTime > samplingInterval)
        {
          readings[arrayIndex++] = analogRead(ORP_PIN);
          samplingTime = millis();
        }
    
      voltage = avergearray( readings, arrayLenth ) * 3.31 / 1024.0;
      orp = ( 2.5 - voltage ) / 1.037 ;
    
      Serial.print("ORP Probe voltage:");
      Serial.print( voltage, 4);
      Serial.print("    ORP value: ");
      Serial.println( orp, 2 );  
      dif = old_orp - orp;
      if ( abs( dif ) > 0.005 ) {
         old_orp = orp; 
         send( orp_msg.set( orp , 2 ) ) ;
         send( var2_msg.set( voltage, 4) ); 
      }
    
      /////////// Sleep
      digitalWrite( POWER , false );
      Serial.println("5V Power OFF");
    
      Serial.print("Runtime: ");
      time();
      Serial.println("Pausing...");
      Serial.println("----------------------------");
      
      //delay(715000);
      wait(500);
      sleep( 715000U );   // Sleeps for 12m
    
    }
    
    double avergearray(int* arr, int number) {
      int i;
      int max, min;
      double avg;
      long amount = 0;
      if (number <= 0) {
        Serial.println("Error number for the array to avraging!/n");
        return 0;
      }
      if (number < 5) { //less than 5, calculated directly statistics
        for (i = 0; i < number; i++) {
          amount += arr[i];
        }
        avg = amount / number;
        return avg;
      } else {
        if (arr[0] < arr[1]) {
          min = arr[0]; max = arr[1];
        }
        else {
          min = arr[1]; max = arr[0];
        }
        for (i = 2; i < number; i++) {
          if (arr[i] < min) {
            amount += min;      //arr<min
            min = arr[i];
          } else {
            if (arr[i] > max) {
              amount += max;  //arr>max
              max = arr[i];
            } else {
              amount += arr[i]; //min<=arr<=max
            }
          }//if
        }//for
        avg = (double)amount / (number - 2);
      }//if
      return avg;
    }
    
    
    void time() {
    
      long timeNow = millis();
    
      int days = timeNow / day ;                                //number of days
      int hours = (timeNow % day) / hour;                       //the remainder from days division (in milliseconds) divided by hours, this gives the full hours
      int minutes = ((timeNow % day) % hour) / minute ;         //and so on...
      int seconds = (((timeNow % day) % hour) % minute) / second;
    
      // digital clock display of current time
      Serial.print(days, DEC);
      printDigits(hours);
      printDigits(minutes);
      printDigits(seconds);
      Serial.println();
    
    }
    
    void printDigits(byte digits) {
      // utility function for digital clock display: prints colon and leading 0
      Serial.print(":");
      if (digits < 10)
        Serial.print('0');
      Serial.print(digits, DEC);
    }
    
    
    /* Read internal Vcc reference 
     *  
     */
    float readVcc()
    {
      signed long resultVcc;
      float resultVccFloat;
      // Read 1.1V reference against AVcc
      ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
      delay(10);                           // Wait for Vref to settle
      ADCSRA |= _BV(ADSC);                 // Convert
      while (bit_is_set(ADCSRA, ADSC));
      resultVcc = ADCL;
      resultVcc |= ADCH << 8;
      resultVcc = 1126400L / resultVcc;    // Back-calculate AVcc in mV
      resultVccFloat = (float) resultVcc / 1000.0; // Convert to Float
    
      return resultVccFloat;
    }
    
    Development

  • Merge Help: Door+ BME280
    rvendrameR rvendrame

    @Puneit-Thukral I have a similar sensor ( PIR + BMP280 + other stuff). I don't use smartSleep ( Since this code is old, only sleep was available ) so I can't speak about the sleep part. Maybe you could try with regular sleep just to see if brings some diference...

    Regarding the BME280 (BMP in my case) , I didn't have to use the Wire.begin() / end(), and I use the same library as yours (Adafruit).

    Code is bellow, in case you want to compare yourself.

    /**
     * The MySensors Arduino library handles the wireless radio link and protocol
     * between your home built sensors/actuators and HA controller of choice.
     * The sensors forms a self healing radio network with optional repeaters. Each
     * repeater and gateway builds a routing tables in EEPROM which keeps track of the
     * network topology allowing messages to be routed to nodes.
     *
     * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
     * Copyright (C) 2013-2015 Sensnology AB
     * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
     *
     * Documentation: http://www.mysensors.org
     * Support Forum: http://forum.mysensors.org
     *
     * This program is free software; you can redistribute it and/or
     * modify it under the terms of the GNU General Public License
     * version 2 as published by the Free Software Foundation.
     *
     *******************************
     *
     * REVISION HISTORY
     * (adopted from 5in1 V2.1)
     * Version 3.0 - RV -  Shifted to BMP280 sensor, added pressure and water leakage (via ROPE  https://www.amazon.com/gp/product/B004FTFQ4W/ref=ppx_od_dt_b_asin_title_s01?ie=UTF8&psc=1 ) 
     * 
     * 
     * DESCRIPTION
     * BMP280 on std SDA/SDL pins  (Temp/Pressure) 
     * LDR on pin A1:  GND ---> 10k ---> A1 <-- LDR  <-- Vcc 
     * PIR on D3 and wakeup via interrupt (in case of PIR trigger) 
     * Smoke on D2 with interrupt wake up too. ( 4n25 4K7 on buzzer, 2M7 Pullup resistor recommended ) 
     * Water Sensing cable on A2:  GND --> 100k --> A2 <--  X--X <-- Vcc  
     * (https://www.amazon.com/gp/product/B004FTFQ4W/ref=ppx_od_dt_b_asin_title_s01?ie=UTF8&psc=1)
     * 
     * Battery voltage is as battery percentage (Internal message), and optionally as a sensor value (See defines below)
     *
     */
    
    // Enable debug prints to serial monitor
    #define MY_DEBUG 
    
    // Board type 
    #define DRAGON  // PRO_MINI //  DRAGON / SENSEBENDER
    
    // Define a static node address, AUTO or 1-255 fixed
    #define MY_NODE_ID 25 // AUTO 
    #define MY_PARENT_NODE_ID AUTO 
    
    // Enable and select radio type attached
    #define MY_RADIO_RF24  // MY_RADIO_RFM69
    
    // Uncomment the line below, to transmit battery voltage as a normal sensor value
    #define BATT_SENSOR    199
    
    #define NAME "8in1 Sensor"
    #define RELEASE "3.3"
    
    // Pin definitions for sensors
    #define SDA_PIN        A5    // Just to document std IC2 interface 
    #define SCL_PIN        A4    // Just to document std IC2 interface 
    #define LDR_PIN        A1    //  Analog Light sensor (LDR)
    #define WATER_PIN      A2    //  Analog Water Leak sensor (rope)
    #define SMOKE_PIN      2     //  Digital Smoke sensor (0/1)
    #define PIR_PIN        3     //  PIR Sensor (0/1) 
    #define TRIGGER_PIN    4     //  Trigger for HC-SR04 sensor 
    #define ECHO_PIN       5     //  Echo for HC-SR04 sensor 
    
    #ifdef DRAGON
    //   #define SPIFLASH_PIN   8 
       #define LED_PIN        9  
       #define TEST_PIN       A0
       #define MY_RF24_CE_PIN  7  
       #define MY_RF24_CS_PIN  10 
    //   #define MY_SOFTSPI
    //   #define MY_SOFT_SPI_SCK_PIN     13
    //   #define MY_SOFT_SPI_MISO_PIN    12
    //   #define MY_SOFT_SPI_MOSI_PIN    11
    #endif
    
    #ifdef SENSEBENDER
       #define SPIFLASH_PIN   8 
       #define TEST_PIN       A0
       #define OTA_ENABLE     A1
       #define LED_PIN        A2
       #define ATSHA204_PIN   17 // A3
    #endif
    
    #ifdef PRO_MINI
      #define LED_PIN 8
    #endif
    
    // Includes ///////////////////////////////////////////
    #include <SPIMemory.h> 
    #include <SPI.h>
    #include <MySensors.h>
    //#include <Wire.h>
    //#include <EEPROM.h>  
    //#include <sha204_library.h>
    //#include <Adafruit_Sensor.h>
    #include <Adafruit_BMP280.h>
    
    /// Sketch parameters SETUP ////////////////////////////
    // Child sensor ID's
    #define CHILD_ID_TEMP  1
    #define CHILD_ID_HUM   2
    #define CHILD_ID_PRESS 3
    #define CHILD_ID_LIGHT 4
    #define CHILD_ID_PIR   5
    #define CHILD_ID_SMOKE 6
    #define CHILD_ID_WATER 7 
    #define CHILD_ID_TANK  8 
    
    // How many milli seconds should we wait for OTA?
    #define OTA_WAIT_PERIOD 500
    
    // How many milli seconds between each measurement
    #define MEASURE_INTERVAL 720000   // 12min 
    
    // How many wakeups to send battery level 
    #define BAT_INTERVAL     100      //  around 20 hours 
    
    // FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller
    #define FORCE_TRANSMIT_INTERVAL 10 //  around 2 hours 
    
    // 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 5
    #define TEMP_TRANSMIT_THRESHOLD 0.5
    #define LIGHT_TRANSMIT_THRESHOLD 5
    #define PRESS_TRANSMIT_THRESHOLD 50
    
    // Flash memory 
    #ifdef SPIFLASH_PIN 
    SPIFlash flash( SPIFLASH_PIN );
    #endif
    
    // ATSHA204
    #ifdef ATSHA204_PIN
    atsha204Class sha204( ATSHA204_PIN );
    #endif
    
    //Weather Sensor BMP280 on IC2 (Temp/Hum/Pressure):
    #ifdef SDA_PIN and SCL_PIN 
    Adafruit_BMP280 weather_sensor;
    #endif
    
    // Sensor messages
    MyMessage msgHum(CHILD_ID_HUM, V_HUM);
    MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
    MyMessage msgPressure(CHILD_ID_PRESS, V_PRESSURE ); 
    MyMessage msgLight(CHILD_ID_LIGHT, V_LIGHT_LEVEL);
    MyMessage msgMotion(CHILD_ID_PIR, V_TRIPPED); 
    MyMessage msgSmoke(CHILD_ID_SMOKE, V_TRIPPED ); 
    MyMessage msgWater(CHILD_ID_WATER, V_TRIPPED ); 
    MyMessage msgDist(CHILD_ID_TANK, V_DISTANCE ); 
    
    #ifdef BATT_SENSOR
    MyMessage msgBatt(BATT_SENSOR, V_VOLTAGE);
    #endif
    
    // Global settings
    int measureCount;
    int sendBattery;
    boolean isMetric = true;
    boolean highfreq = true;
    boolean transmission_occured = false;
    
    // Storage of old measurements
    float lastTemperature = -100;
    float lastHumidity = -100;
    float lastPressure = -100; 
    long lastBattery = -100;
    int lastPir = -1;  
    int lastLight = -100; 
    int lastSmoke = -1; 
    int lastWater = -1; 
    int lastDist = -1; 
    
    /****************************************************
     *
     * Setup code 
     *
     ****************************************************/
    void setup() {
    
      #ifdef LED_PIN 
      pinMode(LED_PIN, OUTPUT);
      digitalWrite(LED_PIN, HIGH);
      #endif
      
      Serial.begin( MY_BAUD_RATE );  // Default for MySensors is 115200 
    
    // Test Mode  //////////////////////////
      #ifdef TEST_PIN
      pinMode(TEST_PIN,INPUT_PULLUP);
      if (!digitalRead(TEST_PIN)) testMode();
      pinMode(TEST_PIN,INPUT); 
      #endif
    
    // Pin Mode Setup //////////////////////
      #ifdef BAT_PIN 
      pinMode(BAT_PIN , INPUT);  // Ext. Batery meter (1M / 470K resistors) 
      #endif 
      #ifdef SMOKE_PIN
      pinMode(SMOKE_PIN , INPUT ); 
      #endif
      #ifdef PIR_PIN
      pinMode(PIR_PIN , INPUT);   
      #endif 
      #ifdef TRIGGER_PIN
      pinMode(PIR_PIN , OUTPUT);   
      #endif 
      #ifdef ECHO_PIN
      pinMode(ECHO_PIN , INPUT);   
      #endif 
        
    // Startup Info 
      Serial.print("Board:");
      Serial.print( ARDUINO ); 
      Serial.print( "\t" ); 
      Serial.print( F_CPU / 1000000 ); 
    
      Serial.print(" Mhz\t"); 
      Serial.print( NAME );
      Serial.print(" "); 
      Serial.println( RELEASE );
     
      Serial.print("Nrf24 CE/CS:");
      Serial.print( MY_RF24_CE_PIN);  
      Serial.print("/"); 
      Serial.print( MY_RF24_CS_PIN ); 
    
      Serial.print("\tNODE ID:");
      Serial.print(hwReadConfig(EEPROM_NODE_ID_ADDRESS));
      
      isMetric = getControllerConfig().isMetric;
      Serial.print(F("\tisMetric:")); Serial.println(isMetric);
      
      #ifdef OTA_WAIT_PERIOD
      Serial.print("OTA FW Enabled"); 
      #endif
    
      // SPI Flash 
      #ifdef SPIFLASH_PIN
      SPI.begin(); 
      Serial.print(F("\tFlash:")); 
      if ( flash.begin() ) { 
        Serial.print( flash.getCapacity() / 8000 , 0 );
        Serial.print( "KB"); 
        flash.powerDown(); 
      } else Serial.print( flash.error(VERBOSE) ); 
    
      #endif
    
      // BMP280 init ////////////////////////
      #ifdef SDA_PIN and SCL_PIN
      Serial.print(F("\tBMP280:")); 
      if ( weather_sensor.begin() ) { 
        Serial.print(F("OK"));
        /* Default settings from datasheet. */
        weather_sensor.setSampling(Adafruit_BMP280::MODE_NORMAL,     /* Operating Mode. */
                      Adafruit_BMP280::SAMPLING_X1,       /* Temp. oversampling */
                      Adafruit_BMP280::SAMPLING_X1,       /* Pressure oversampling */
                      Adafruit_BMP280::FILTER_OFF );      /* Filtering. */
    
      } else Serial.print(F("ERROR!")); 
      #endif
    
      // Force 1st transmission of all sensors
      measureCount = FORCE_TRANSMIT_INTERVAL;
      sendBattery = BAT_INTERVAL; 
      
      #ifdef LED_PIN 
      digitalWrite(LED_PIN, LOW);
      #endif
        
      Serial.println(F("\n///////////////////// ONLINE /////////////////////"));
      Serial.flush(); 
    
    }
    
    void presentation() { 
    
      sendSketchInfo( NAME , RELEASE);
      #ifdef SDA_PIN 
        present(CHILD_ID_TEMP,S_TEMP);
        present(CHILD_ID_HUM,S_HUM);
        present(CHILD_ID_PRESS, S_BARO ); 
      #endif
      #ifdef LDR_PIN
        present(CHILD_ID_LIGHT,S_LIGHT_LEVEL);
      #endif
      #ifdef PIR_PIN 
        present(CHILD_ID_PIR,S_MOTION); 
      #endif
      #ifdef SMOKE_PIN 
        present(CHILD_ID_SMOKE, S_SMOKE); 
      #endif 
      #ifdef WATER_PIN
        present(CHILD_ID_WATER, S_WATER_LEAK ); 
      #endif
      #ifdef TRIGER_PIN
        present(CHILD_ID_TANK, S_DISTANCE ); 
      #endif
      #ifdef BATT_SENSOR
        present(BATT_SENSOR, S_POWER);
      #endif
     
    }
    
    /***********************************************
     *
     *  Main loop function
     *
     ***********************************************/
    void loop() {
    
      #ifdef LED_PIN
      digitalWrite( LED_PIN , HIGH ); 
      #endif
      
      boolean forceTransmit = false;
      transmission_occured = false; 
      
      if ( ++measureCount > FORCE_TRANSMIT_INTERVAL ) { // force a transmission
        forceTransmit = true;
        Serial.print(F("[Force Transmission]"));  
        measureCount = 0;
      }
    
      // Light, PIR, Smoke, Water leak 
      sendLight(forceTransmit); 
      sendPir(forceTransmit); 
      sendSmoke(forceTransmit); 
      sendWater(forceTransmit);
      sendWeather(forceTransmit);  
      sendDistance(forceTransmit); 
      
      // Battery level report 
      if ( ++sendBattery > BAT_INTERVAL ) {
           sendBattLevel(true); 
           sendBattery = 0;
      }
    
      // Wait for FW update... 
      if (transmission_occured) {
          wait(OTA_WAIT_PERIOD);
          measureCount = 0; 
      }
    
      #ifdef LED_PIN
      digitalWrite( LED_PIN , LOW ); 
      #endif
    
      Serial.println(); 
    
      // Trick to avoid false triggering on PIR 
      sleep(1000); 
      
      // Sleep until interval or PIR or smoke trigger 
      if ( lastSmoke == 1 )  // In case of Smoke Alarm, don't sleep too much... 
          sleep( 45000 ); 
      else if ( lastPir == 1 )  // In case of Motion, stop PIR detecting for 1 complete cycle... 
          sleep( 0 , CHANGE , MEASURE_INTERVAL ); 
      else 
          sleep( 0 , CHANGE , 1 , CHANGE, MEASURE_INTERVAL); // Default: Wake up on any PIR and Smoke... 
    
      // To avoid false Smoke alarm
      wait(100); 
    
      // Wake
      Serial.print( millis() ); 
      Serial.print("[WAKE]"); 
    
    }
    
    /*********************************************
     *
     * Sends Motion status 
     *
     *********************************************/
    void sendDistance(bool force)
    {
    
    long duration;
    int distance;
    
       #ifdef TRIGER_PIN
       digitalWrite( TRIGER_PIN, LOW);
       delayMicroseconds(2);
       digitalWrite( TRIGER_PIN , HIGH);
       delayMicroseconds(10);
       digitalWrite( TRIGER_PIN , LOW);
       // Reads the echoPin, returns the sound wave travel time in microseconds
       duration = pulseIn( ECHO_PIN , HIGH);
       // Calculating the distance
       distance = duration * 0.034 / 2;
       if ( distance != lastDist || force ) { 
          Serial.print(" D:");Serial.print(distance);
          send(msgDist.set(distance));
          transmission_occured = true; 
          lastDist = distance; 
       }
       #endif 
       
    }
    
    /*********************************************
     *
     * Sends Motion status 
     *
     *********************************************/
    void sendPir(bool force)
    {
    
       #ifdef PIR_PIN
       int currPir = digitalRead( PIR_PIN ); 
       if ( lastPir != currPir || force ) { 
          Serial.print(" M:");Serial.print(currPir);
          send(msgMotion.set(currPir));
          transmission_occured = true; 
          lastPir = currPir; 
       }
       #endif 
       
    }
      
    /*********************************************
     *
     * Sends Smoke status 
     *
     *********************************************/
    void sendSmoke(bool force)
    {
    
       #ifdef SMOKE_PIN
       int currSmoke = !digitalRead( SMOKE_PIN ); // Low = Smoke Triggered 
       if ( lastSmoke != currSmoke || force ) { 
          Serial.print(" S:");Serial.print(currSmoke);
          send(msgSmoke.set(currSmoke));
          transmission_occured = true; 
          lastSmoke = currSmoke;    
       }
       #endif 
    }
    
    /*********************************************
     *
     * Sends Smoke status 
     *
     *********************************************/
    void sendWater(bool force)
    {
    
       #ifdef WATER_PIN 
       int currWater = ( analogRead( WATER_PIN ) > 500 ? 1 : 0 ) ;  
       //Serial.println( analogRead( WATER_PIN ) ); 
       if ( lastWater != currWater || force ) { 
          Serial.print(" W:");Serial.print(currWater);
          send(msgWater.set(currWater));
          transmission_occured = true; 
          lastWater = currWater;    
       }
       #endif
    }
    
    /*********************************************
     *
     * Sends Light Level based on LDR 
     *
     * Parameters
     * - force : Forces transmission of a value (even if it's the same as previous measurement)
     *
     *********************************************/
    void sendLight(bool force)
    {
      #ifdef LDR_PIN 
      int currLight = map( analogRead( LDR_PIN ) , 0, 1024 , 0 , 100 ); 
      int diffLight = abs( lastLight - currLight );  
      if (isnan(diffLight) || diffLight >= LIGHT_TRANSMIT_THRESHOLD || force )  {
        Serial.print(" L:");Serial.print(currLight);
        send(msgLight.set(currLight));
        lastLight = currLight; 
        transmission_occured = true; 
      }
      #endif 
    }
    
    /*********************************************
     *
     * Sends temperature and humidity from Si7021 sensor
     *
     * Parameters
     * - force : Forces transmission of a value (even if it's the same as previous measurement)
     *
     *********************************************/
    void sendWeather(bool force)
    {
      #ifdef SDA_PIN and SCL_PIN 
      bool tx = force;
      
      // Sensor reading 
      float temp = weather_sensor.readTemperature();  
      //float humd = "N/A" ;  // Hum is not supported on BMP280  (But it is in BME280) 
      float pres = weather_sensor.readPressure(); 
      
       // Temperature delta 
      float diffTemp = abs( lastTemperature - temp );
      if (diffTemp >= TEMP_TRANSMIT_THRESHOLD) tx = true;
    
      // Humidity delta
      //float diffHum = abs( lastHumidity - humd ); 
      //if ( isnan(diffHum) || diffHum >= HUMI_TRANSMIT_THRESHOLD) tx = true;
    
      // Pressure delta 
      float diffPress = abs( lastPressure - pres );
      if (diffPress >= PRESS_TRANSMIT_THRESHOLD) tx = true;
    
      if (tx) {
        
        measureCount = 0;
         
        Serial.print(" T:");Serial.print(temp,1);
        //Serial.print(" H:");Serial.print(humd,1);
        Serial.print(" P:");Serial.print(pres,1); 
        
        send(msgTemp.set(temp,1));
        //send(msgHum.set(humd,1));
        send(msgPressure.set(pres,1)); 
       
        lastTemperature = temp;
        //lastHumidity = humd;
        lastPressure = pres; 
        
        transmission_occured = true;
             
      } 
    
      // BUG? High consumption ... 
      //digitalWrite( SDA_PIN , LOW ); 
      //digitalWrite( SCL_PIN , LOW ); 
      
      #endif 
    }
    
    /********************************************
     *
     * Sends battery information (battery percentage)
     *
     * Parameters
     * - force : Forces transmission of a value
     *
     *******************************************/
    void sendBattLevel(bool force)
    {
    
      #ifdef BAT_PIN
      long vcc = ( analogRead( BAT_PIN ) * 3300.0 / 1024.0 ) * 3.13; 
      #else
      long vcc = readVcc(); 
      #endif 
       
      if ( abs( ( vcc - lastBattery ) ) > 100 || force) {
    
        lastBattery = vcc;
    
        #ifdef BATT_SENSOR
        float send_voltage = float(vcc)/1000.0f;
        send(msgBatt.set(send_voltage,3));
        #endif
    
        // Calculate percentage
        vcc = vcc - 1900; // subtract 1.9V from vcc, as this is the lowest voltage we will operate at 
        long percent = vcc / 13.0;
        //long percent = constrain( map( vcc, 4000 , 9000, 0, 100 ) , 0 , 100 );  
        Serial.print(" Batt%:"); Serial.print( percent ); 
        sendBatteryLevel(percent);
        transmission_occured = true; 
        
      }
      
    }
    
    /*******************************************
     *
     * 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
    }
    
    
    /****************************************************
     *
     * Verify all peripherals, and signal via the LED if any problems.
     *
     ****************************************************/
    void testMode()
    {
      uint8_t rx_buffer[SHA204_RSP_SIZE_MAX];
      uint8_t ret_code;
      boolean fail = false; 
    
      #ifdef LED_PIN 
      digitalWrite(LED_PIN, HIGH); // Turn on LED.
      #endif
      
      Serial.println(F(" - TestMode"));
      Serial.println(F("Testing peripherals!"));
      Serial.flush();
    
      #ifdef SDA_PIN 
      Serial.print(F(" IC2 weather sensor ")); 
      Serial.flush();
      if ( weather_sensor.begin() && weather_sensor.readPressure() &&  
           weather_sensor.readTemperature() > 900 ) 
      {
        Serial.println(F("ok!"));
      }
      else
      {
        Serial.println(F("failed!"));
        fail = true; 
      }
      Serial.flush();
      #endif
      
      #ifdef SPIFLASH_PIN
      Serial.print(F("-> Flash : "));
      Serial.flush();
      if (flash.begin())
      {
        Serial.println(F("ok!"));
      }
      else
      {
        Serial.println(F("failed!"));
        fail = true; 
      }
      Serial.flush();
      #endif 
      
      #ifdef ATSHA204_PIN
      Serial.print(F("-> SHA204 : "));
      ret_code = sha204.sha204c_wakeup(rx_buffer);
      Serial.flush();
      if (ret_code != SHA204_SUCCESS)
      {
        Serial.print(F("Failed to wake device. Response: ")); Serial.println(ret_code, HEX);
      }
      Serial.flush();
      if (ret_code == SHA204_SUCCESS)
      {
        ret_code = sha204.getSerialNumber(rx_buffer);
        if (ret_code != SHA204_SUCCESS)
        {
          Serial.print(F("Failed to obtain device serial number. Response: ")); Serial.println(ret_code, HEX);
          fail = true; 
        }
        else
        {
          Serial.print(F("Ok (serial : "));
          for (int i=0; i<9; i++)
          {
            if (rx_buffer[i] < 0x10) Serial.print('0'); // Because Serial.print does not 0-pad HEX
            Serial.print(rx_buffer[i], HEX);
          }
          Serial.println(")");
        }
    
      }
      Serial.flush();
      #endif 
      
      Serial.println(F("Test finished"));
      
      if ( !fail ) 
      {
        Serial.println(F("Selftest ok!"));
        while (1) // Blink OK pattern!
        {
          #ifdef LED_PIN 
          digitalWrite(LED_PIN, HIGH);
          delay(200);
          digitalWrite(LED_PIN, LOW);
          delay(200);
          #endif
        }
      }
      else 
      {
        Serial.println(F("----> Selftest failed!"));
        while (1) // Blink FAILED pattern! Rappidly blinking..
        {
        }
      }  
    }
    
    Development
  • Login

  • Don't have an account? Register

  • Login or register to search.
  • First post
    Last post
0
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular