Navigation

    • Register
    • Login
    • OpenHardware.io
    • Categories
    • Recent
    • Tags
    • Popular
    1. Home
    2. rvendrame
    3. Best
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    Best posts made by rvendrame

    • RE: 3.3 or 5v tranformer for mysensors projects

      @Tmaster , we have discussed the LNK302 chip a while ago, it may be interesting to check: https://forum.mysensors.org/search?term=lnk302&in=titlesposts

      I did POC here, and it does work, but I was a bit afraid of non-isolation so I decided to use the Hi-Link, assuming it would be more safe (and less components to assembly). I'm running a couple of nodes with Hi-Link for ~2 years without a glitch.

      The classic transformer approach for sure brings more isolation and safety. Also it is a good choice if you want to detect zero-cross (for AC dimmers) and measure real power consumption (by reading the real AC voltage from the transformer's AC output). On the other hand I see the bigger footprint as well as more components to assembly.

      Just my two cents...

      posted in Hardware
      rvendrame
      rvendrame
    • RE: Transformer-less power supply

      Despite the security (which of course is the most important aspect here), such kind of circuit usually consumes from 2 to 10w (depending on AC voltage and C1 value), no matter in standby or not. I did some testing in the past and at end I dropped in favor of hi-link and similar small PSUs.

      posted in My Project
      rvendrame
      rvendrame
    • RE: Safe In-Wall AC to DC Transformers??

      The review of the hlktech's HLK-PM01 is available here!

      posted in Hardware
      rvendrame
      rvendrame
    • RE: Transformer-less power supply

      You can find "Hi-link like" PSUs at Aliexpress for less than $2 USD. Not sure how less you can reach by producing them by yourself.

      posted in My Project
      rvendrame
      rvendrame
    • RE: Sensebender Micro

      Batteries usually provide a 'clean' power supply. The capacitor is more useful when there is ripple from the AC adapter.

      posted in Announcements
      rvendrame
      rvendrame
    • RE: Difficulties compiling Nodemcu 1.0 (ESP-12 module) as a 8266 Gateway.

      @ramwal Thanks for the hint, it made the trick here too!

      posted in Troubleshooting
      rvendrame
      rvendrame
    • RE: Multi Button Relay switch

      @jeylites you can also try adding some delay between each gw.send or gw.present. In my case it did the difference.

      posted in Hardware
      rvendrame
      rvendrame
    • RE: Trying to do a 3 dimmer Led controller with motion

      By using built-in PWM you are limited to 3 outputs (3, 5 and 6), as pins 9, 10 and 11 are being used to connect to nRF radio).

      To read the rotaries you need at least two pins for each ( = "2-bit gray code"). Most rotaries have a 3rd microswitch, and work as a push-button as well, so a extra pin will allow you to have a on-off switch by pushing (instead turning) the rotary .

      Below is my sketch with 3 dimmers (using timers). If you implement timers, you can use any pin. (and it also works with AC-Triacs --- Be careful!!!) . If you are dimming AC bulbs, you need to adjust the 'freqStep' variable according to the AC frequency of your region.

       int freqStep = 84;                   // Microseconds of each tic  =  1s / 60Hz * 100 steps 
      

      I also recommend a 16Mhz Arduino, so you have enough speed to achieve good fade effects in all 3 channels while not missing any radio message.

      Dimmer 1 & 2 can be controlled by rotaries connected on (A3,A4) and (A5,A6). I also use A0 and A1 to immediate on/off by pushing each rotary. Dimmer 3 can only be increased/decreased via Incoming message (although it has a local on/off switch on pin A2).

      Hope it helps!

      /*** 
       * 
       * 3x Bulb/Led dimmer
       * 
       ***/
      
      #include <TimerOne.h> 
      #include <MySensor.h> 
      #include <SPI.h>
      #include <IRLib.h>
      
      #define SN "theDimmer"
      #define SV "1.3"
      
      // Version history
      // 1.2 4-Apr-15: Include "fade to level" logic
      // 1.3 11-Apr-15:  Changed A0-A6 input pins order; code cleanup
      
      // MySensor gateway, dimmer & light messages
      MySensor gw; 
      MyMessage msg1[3];
      MyMessage msg2[3]; 
      
      // Infrared Send module 
      IRsend irsend;
      
      // Warning message
      MyMessage var1( 0 , V_VAR1); 
      volatile boolean AC_found = false; 
      
      // Dim Level 
      int level[3] ;    // Current dim level on OUTPUT pins (0 to 100)
      int level_gw[3];  // Current dim level at Controller 
      int level_tg[3];  // Current dim level (target)
      float gap; 
      
      // Output pins (to Triacs / MOSFETs)
      int out_pin[3] = { 5, 6, 7 };  // Output PINS
      
      // Input: local rotary encoders (only 2) - 2-bit gray code
      int a,b,oldA[2],oldB[2];
      int rotary[2][2] = {  { A3 , A4 }  ,  { A5, A6 } };  // INPUT PINS
      
      // Input: local switches
      boolean newSw, oldSw[3]; 
      long lastSw[3];  
      int sw[3] = { A0, A1, A2 };  // INPUT PINS 
      
      // Infrared Emiiter Pin
      #define IR_PIN 3
      unsigned long raw[400];   // raw sequence of IR codes
      
      // Clock ticker (100 tics = 1 AC wave cycle = 1s / 120Hz = 8333 milisecs
      volatile int counter = 100;          // Timer tick counter
      int freqStep = 84;                   // Microseconds of each tic  =  1s / 60Hz * 100 steps 
      volatile boolean zero_cross = false; // Zero-cross flag
      int zero_cross_pin = 2;             // Input PIN for zero-cross detection 
      volatile int int_ct = 0 ; 
      
      // Idle counter (for gw update); 
      boolean idle; 
      int idle_ct; 
      
      void setup() { 
      
        // Serial init
        Serial.begin(115200); 
        
        // Start radio Controller
        gw.begin( incomingMessage );
        gw.sendSketchInfo( SN, SV );
      
        // IR output available? 
        pinMode( IR_PIN, INPUT );
        delay(50); 
        if ( digitalRead( IR_PIN ) == LOW ) { 
          pinMode( IR_PIN , OUTPUT );   
          gw.present( 4 , S_IR ); 
          Serial.println("IR init"); 
        } 
      
        // Setup IN/OUT pins
        for (int i = 0; i < 3; i++ ) { 
      
          // levels / step
          level[i] = 0;
          level_gw[i]=0;
          level_tg[i]=0; 
          
          // Create return messages
          msg1[i] = MyMessage( i , V_DIMMER ) ; 
          msg2[i] = MyMessage( i , V_LIGHT ) ; 
      
          // Rotary Encoders
          if ( i < 2) { 
            pinMode( rotary[i][0] , INPUT_PULLUP );
            pinMode( rotary[i][1] , INPUT_PULLUP ); 
            oldA[i] = digitalRead( rotary[i][0] );
            oldB[i] = digitalRead( rotary[i][1] );
          } 
      
          // Input Switches/PBs
          pinMode( sw[i] , INPUT_PULLUP );
          oldSw[i] = digitalRead( sw[i] ); 
          lastSw[i] = millis(); 
      
          // Triac/MOSFET out
          pinMode( out_pin[i], INPUT ); 
          delay(50);
          if ( digitalRead( out_pin[i] ) == LOW ) { 
      
            pinMode( out_pin[i] , OUTPUT ); 
            digitalWrite( out_pin[i], LOW );  
      
            // Register Dimmable Lights with the gateway
            gw.present( i, S_DIMMER );
           
            // Fetchs previous state from controller
            gw.request( i , V_DIMMER ); 
      
            Serial.print("Dimmer init CH "); 
            Serial.println( i );  
      
          } 
      
        } 
      
        // Zero-cross detection on Pin 2 
        pinMode( zero_cross_pin , INPUT_PULLUP);
        attachInterrupt( 0, zero_cross_detect, RISING );  
      
        // Clock ticker
        Timer1.initialize(); 
        Timer1.attachInterrupt( dim_check , freqStep ); 
      
      } 
      
      // Zero-cross
      void zero_cross_detect() { 
        
        zero_cross = true;
        AC_found = true; 
        counter = 100; 
        for (int i=0; i<3; i++)  digitalWrite( out_pin[i], LOW ) ; 
      
      } 
      
      // Timer Ticker - check
      void dim_check() { 
      
        int j = 0; 
      
        if ( zero_cross == true ) { 
      
          for (int i=0; i<3; i++)  
            if ( counter <= level[i] ) { 
              digitalWrite( out_pin[i] , HIGH ); 
              j++;
            } 
         
      
          // If all 3 output fires, avoid further checks... 
          if ( j == 3) zero_cross = false; 
        } 
      
        // Tic-tac...
        counter--; 
      
        // No zero-cross circuit?  As contingency, emulate it based on timer 
        // (Should work at least for PWM led running by  MOSFET )
        if ( counter == 0 ) { 
      
          zero_cross = true;
          counter = 100; 
          for (int i=0; i<3; i++)  digitalWrite( out_pin[i], LOW ) ; 
        } 
      
      }
      
      void loop() { 
      
        // Automation controller
        gw.process();
      
        // Idle flag
        idle = true; 
      
        // gap step calculation 
        gap = 0.0; 
        
        // Smooth transition to target level 
        for (int i=0; i<3; i++) { 
          if ( level[i] != level_tg[i] )  { 
             gap = ( ( level_tg[i] - level[i] ) / 25.0 );
             if ( gap > 0.0 && gap < 1.0 ) gap = 1.0 ;
             if ( gap < 0.0 && gap > -1.0 ) gap = -1.0;        
                   level[i] += gap;              
          } 
        }  
        
        // Small delay to produce the fade effect 
        if ( gap != 0 )   delay(27);  // Aprox. .7s  (=700/25) of ramp up/down 
             
        // Read the Rotary Encoders
        for (int i=0; i<2; i++) { 
      
          // Read current state
          a = digitalRead( rotary[i][0] );
          b = digitalRead( rotary[i][1] ); 
      
          // Any change? 
          if ( a != oldA[i] || b != oldB[i] ) { 
      
            idle = false; 
            idle_ct = 0; 
      
            if ( oldA[i] == LOW && oldB[i] == LOW ) {  
      
              a == HIGH ?  level[i]-=8 : level[i]+=8 ; 
      
              if ( level_tg[i] > 100 )  level_tg[i] = 100; 
              if ( level_tg[i] < 0 )    level_tg[i] = 0; 
      
            }
        
            // Save to use later... 
            oldA[i] = a;
            oldB[i] = b; 
            delay(3);  
          }  
        } 
      
        // Read local Push button
        for (int i=0; i<3; i++) { 
          
          // Check SWs
          newSw = digitalRead( sw[i] ); 
      
          // Any change? 
          if ( newSw != oldSw[i] ) { 
      
            // Not idle anymore... 
            idle = false; 
            idle_ct =  0; 
      
            // Minimum push to swap state
            if ( millis() - lastSw[i] > 500 ) { 
      
              level_tg[i] > 0 ? level_tg[i] = 0 : level_tg[i] = 100; 
      
            } 
      
            // Save to use later... 
            oldSw[i] = newSw; 
            lastSw[i] = millis();
            delay(50); 
      
          } 
      
        }
      
        if (idle) { 
      
          if ( ++idle_ct > 15000 ) {   // (about 1s) 
      
            // Check for not-updated levels on GW-controller
            for (int i=0; i<3; i++) { 
      
              // Update Level in GW-controller
              if ( level_gw[i] != level[i] ) { 
      
                // update GW-controller
                // Send new state and request ack back
                gw.send( msg1[i].set( level[i] ) ); 
                gw.send( msg2[i].set( level[i] > 0 ? true : false ) );  
                level_gw[i] = level[i]; 
      
              } 
      
              // Warning message for no zero-cross detected 
              if ( !AC_found ) { 
                gw.send( var1.set( "No AC?") ) ; 
                AC_found = true ; 
              } 
            }
      
            // Reset idle counter
            idle_ct = 0; 
          } 
      
        } 
      
      } 
      
      
      void incomingMessage(const MyMessage &message)
      {
      
        // ACK
        if (message.isAck()) {
          // Nothing to do, just ACK from Gateway
          //irsend.send(NEC, 0x1EE17887, 32); // Vol up yamaha ysp-900
         // irsend.send(NEC, 0x1EE1F807, 32); // Vol down yamaha ysp-900
        } 
        else { 
      
          // IR Output 
          if ( message.type == V_IR_SEND )
          { 
            
           // TO DO 
            
          } 
          
          // Light/Dimmer messages 
          if ( message.type == V_LIGHT || message.type == V_DIMMER ) 
          {
      
            //  Retrieve the power or dim level from the incoming request message
            int requestedLevel = atoi( message.data );
      
            // Channel
            int i = message.sensor; 
      
            // Adjust incoming level if this is a V_LIGHT variable update [0 == off, 1 == on]
            requestedLevel *= ( message.type == V_LIGHT ? 100 : 1 );
      
            // Clip incoming level to valid range of 0 to 100
            requestedLevel = requestedLevel > 100 ? 100 : requestedLevel;
            requestedLevel = requestedLevel < 0   ? 0   : requestedLevel;
      
            // Set new level
            level_tg[i] = requestedLevel; 
            level_gw[i] = requestedLevel; 
      
          }
        }
      }
      
      
      posted in My Project
      rvendrame
      rvendrame
    • RE: MyS not working on solar sensor board

      @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> 
      
      posted in Troubleshooting
      rvendrame
      rvendrame
    • RE: Safe In-Wall AC to DC Transformers??

      More from the 'guru'

      "There is no input fuse, that is the reason I recommend one and it has to be a real fuse that blows, not a fuse that will automatic recover. The only time it is supposed to blow is if the converter blows and then you want the mains permanently disconnected. Probably a 0.2A slow fuse will work."

      posted in Hardware
      rvendrame
      rvendrame
    • RE: AC light dimmer with 2x TRIAC

      @jacikaas

      Try changing this line (not tested):

       int dimtime = (75*currentLevel);    // For 60Hz =>65    
      
      

      to

       int dimtime = (75* ( 128-currentLevel) );    // For 60Hz =>65    
      
      

      Also remove this line to avoid the flicker:

      
        analogWrite( LED_PIN, (int)(currentLevel / 100. * 255) );
      

      ... and finally add this line right before the "fadeToLevel( requestedLevel );" , in order to convert 0-100 range into 0-128 range:

       requestedLevel = map( requestedLevel, 0 , 100 , 0 , 128 ); 
      

      Good luck!

      posted in My Project
      rvendrame
      rvendrame
    • RE: Which gateway to choose Serial, Ethernet or MQTT?

      ... and the serial gateway usually is powered by the host USB computer/controller, while the ethernet gateway requires its own power adapter.

      Just adding my two cents 😉

      posted in General Discussion
      rvendrame
      rvendrame
    • RE: Safe In-Wall AC to DC Transformers??

      @petewill . the MOV goes in parallel with HLK input (and not in series like you did).

      It was suggested to use .2A fuses (instead the .75A). And the Thermal fuse should be glued on HLK top (my guess).

      posted in Hardware
      rvendrame
      rvendrame
    • RE: AC light dimmer with 2x TRIAC

      @jacikaas

      You must declare variables as 'volatile' to ensure they will be updated during interrupts. Try changing:

      static int currentLevel = 128;  // Current dim level...
      

      into

      volatile int currentLevel = 128;  // Current dim level...
      

      And to ensure no triac firing at zero level, try something like this at beginning of zero_cross_int() (before the "int dimtime"):

      if ( currentLevel == 0 )  return; 
      

      Good luck again!

      posted in My Project
      rvendrame
      rvendrame
    • RE: Over the air (OTA) bootloading update tutorial?

      @tekka, please add OTA Serial monitor into the Santa Klaus list 😉

      posted in General Discussion
      rvendrame
      rvendrame
    • RE: Mosfet with Ceech board

      You need to connect the LED (+resistor) like this:

      • Positive: Vcc Pin
      • Negative: The pin with the orange/brown wire in your picture.
        the mosfet onboard is N-channel, so it will switch the negative (GND) line.
      posted in Hardware
      rvendrame
      rvendrame
    • RE: 💬 OH 433Mhz Mysensors Bridge

      @LastSamurai , thanks for the great work. I just built one of these and it is working great.

      If your controller accepts long scene numbers (like my Vera does), we have the option to present it as a scene controller, instead individual buttons. The scene number will be the number of the button pressed. That makes life easy to add new panels around the house.

      Bellow is the sketch I created, based on your example. I also added a short/long-press logic, so for example for a 3-button panel, 6 different scenes can be triggered.

      /*
        This is a gateway node between mysensors and 433Mhz devices. A 433Mhz receiver is connected to pin 3 (int 1).
        This works with any 433Mhz device (as long as rc-switch understands the protocol).
      
        This is based on the MySensors network: https://www.mysensors.org
        This uses the rc-switch library to detect button presses: https://github.com/sui77/rc-switch
      
        Written by Oliver Hilsky 07.03.2017
        Adjusted to Scene controller by Ricardo Vendrame  03.06.2017 
      */
      
      #define LONG_PRESS_OFFSET 10000000UL  // Offset for long-press
      #define LONG_PRESS_COUNT  5           // Number of messages for long-press
      
      #define MY_RADIO_NRF24
      //#define MY_NODE_ID 25
      #define MY_BAUD_RATE 115200
      #define MY_DEBUG    // Enables debug messages in the serial log
      #define VCC_PIN 5
      #define GND_PIN 2
      #define RECEIVER_PIN 3
      
      //#include <EEPROM.h>
      #include <SPI.h>
      #include <MyConfig.h>
      #include <MySensor.h>
      //#include <Vcc.h>
      #include <RCSwitch.h>
      
      MySensor gw; 
      MyMessage msgSceneOn( 0 , V_SCENE_ON ); 
      MyMessage msgSceneOff( 0, V_SCENE_OFF ); 
      
      RCSwitch wirelessSwitch = RCSwitch();
      
      // Short/long press control 
      unsigned long lastreceive, count; 
      
      // add the decimal codes for your switches here
      unsigned long received_val; 
      
      void presentation()
      {
         
      #ifdef MY_NODE_ID
        gw.begin(NULL, MY_NODE_ID, false);
      #else
        gw.begin(NULL,AUTO,false);
      #endif
      
        gw.sendSketchInfo("433 Wireless Gateway", "1.0");
        gw.present( 0 , S_SCENE_CONTROLLER );
      
      }
      
      void setup() {
        
        Serial.begin(MY_BAUD_RATE); 
      
        // Power to Radio... 
        pinMode( VCC_PIN , OUTPUT ); 
        pinMode( GND_PIN , OUTPUT ); 
        digitalWrite( GND_PIN , LOW ); 
        digitalWrite( VCC_PIN , HIGH ); 
      
        // mySensors startup
        presentation(); 
        
        // Enable 433 receiving 
        wirelessSwitch.enableReceive(RECEIVER_PIN-2);  // Receiver on interrupt 
        
        Serial.println("Started listening on pin 3 for incoming 433Mhz messages");
      
        lastreceive = millis(); 
        
      }
      
      void loop() {
      
        gw.process(); 
        
        if ( wirelessSwitch.available() ) {  
      
          if ( ( millis() - lastreceive ) <= 200 ) count ++;
            else count = 1; 
            
          received_val = wirelessSwitch.getReceivedValue();
          wirelessSwitch.resetAvailable();
      
          lastreceive = millis(); 
          //Serial.println( lastreceive ); 
          
        }
      
        if ( count >= LONG_PRESS_COUNT || 
         ( ( millis() - lastreceive ) > 200 && count > 0 ) ) {
          
          // Send scene ID to the gateway
          if ( count >= LONG_PRESS_COUNT ) 
             received_val += LONG_PRESS_OFFSET;
              
          gw.send( msgSceneOn.set( received_val )); 
          
          Serial.print("Scene ");
          Serial.print( received_val ); 
          Serial.println( count < LONG_PRESS_COUNT ? " ON" : " OFF"); 
      
          // software debounce
          gw.wait(750); 
          //delay(750);
          count = 0; 
          wirelessSwitch.resetAvailable();
      
      
        } 
      
      }
      
      

      The edge for short/long press is defined by count of messages received (each message takes about 100ms to be received), so the default "5" in the sketch defines >= ~500ms as long press.

      #define LONG_PRESS_COUNT  5           // Number of messages for long-press
      

      And to distinguish between short and long press, a offset is added to the button number, defined here:

      #define LONG_PRESS_OFFSET 10000000UL  // Offset for long-press
      
      posted in OpenHardware.io
      rvendrame
      rvendrame
    • RE: Will the Arduino mini 3.3v give enough stable power for nRF ?

      @ahmedadelhosni , for a definitive answer you must check what kind of regulator your board has, as well as how much each component of your circuit will consume.

      The official pro-mini uses an MIC5205 voltage regulator that can deliver maximum of 150mA.

      Most clones uses a cheaper regulator (such as the 100mA LP2981 that I found in my pro-minis).

      The official nRF24l01 radio consumes about 15mA while transmitting/receiving. You have to add on top of it the arduino itself, as well as any other components that you are powering up.

      And to be on safe side I would not use more than 60-70% of nominal regulator's output.

      Hope it helps...

      posted in General Discussion
      rvendrame
      rvendrame
    • RE: TV on/off monitor using TV USB port

      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

      posted in Hardware
      rvendrame
      rvendrame
    • RE: 💬 Micro (nano) ampere meter (double)

      @Nca78 , updating: I figured out how to connect the load, so I'm done with it (including calibration).

      I changed the original code a bit, as I also wanted it a bit more responsive. I didn't lift pin 15 as you did.

      BTW, what bootloader + clock are you using? Perhaps that could influence? I'm using MYSBootloaderV13pre.hex, 8Mhz internal clock...

      Changes:

      • Less average reading per cycle (from 32 to 4 ) --> Didn't notice significant changes in measurements.
      • More accumulated avg reads ( from 16 to 32 ) --> Just to keep a less volatile avg numbers in display.
      • Change the logic of short/long press. short press (~1s) = change mode, long press (~3s) = Offset.

      In case you want to give it a try...

      // uA meter with HX711
      /*
       PROJECT: MySensors - uA meter with HX711
       PROGRAMMER: AWI
       DATE: 20170414/ last update: 
       FILE: AWI_uA_meter.ino
       LICENSE: Public domain
      
       Performance improvements: rvendrame 
       
      Hardware: tbd Nano ATmega328p board w/ NRF24l01
      	
      Special:
      	program with Arduino Nano
      	
      SUMMARY:
      	Measures mV accross a shunt resistor ~ uA - channel A
      	Measures mV on channel B
      	Modes:
      		- default: measure uV in full resolution (Stable reading only for 0.1uV)
      		- other:
      			A: channel A: default, amplification 128 - div 500: 0.1uV stable,  range +/- 20mV, (1ohm +/- 20mA, res 100 nA)
      			B: channel B: amplification 32 - div 125: 100nA stable, range +/- 80mV,  (10 ohm +/- 8 mA, res 10 nA)
      			AB: both channels:  
      		- uA - calibration: depending on the actual shunt:
      			0.47 ohm -> 1 uV ~ 2uA, range -40 mA - 40 mA
      			1 ohm -> 1 uV = 1uA, range -20 mA - 20 mA
      			10 ohm -> 1 uv = 0.1uA
      		- mV - calibration, depend on amplification
      	Button switch:
      		- Short press, reset current channel to offset 0 (keep terminals shorted, no need with uA ;-)
      		- Long press, change channel A (uA) / B(uA)/ A & B (uA)
      		
      	Hx711 24bit weight scale sensor
      		- Noise and temperature sensitive (x bit effective)
      	OLED 128x64 display
      	
      Remarks:
      	Size is large as result of font library for display
      update:
      	
      */
      
      #include <U8g2lib.h>									// U8glib for OLED display
      #include <Wire.h> 										// I2C
      #include <Button.h>										// https://github.com/JChristensen/Button
      #include "HX711.h"										// local ADC lib
      
      const double calibrationFactorA = 599.18f ;				// calibration for channel A: set to 1.0 for known current and divide
      const double calibrationFactorB = 149.76f ;				// calibration for channel B: set to 1.0 for known current and divide
      long offsetChannelA = 0 ;								// channel offsets for A and B (drifts) are calibrated at startup and on command. 
      long offsetChannelB = 0 ;
      
      const uint8_t HX711_dout = A1 ;							// HX711 data out pin
      const uint8_t HX711_sck = A0 ;							// HX711 serial clock
      const uint8_t buttonPin = A2 ;							// connects the button to select function and reset offset
      //const unsigned long longPress = 1500UL ;				//	- long press set reference temperature - in ms												// 	- when alarm, short press resets alarm	
      Button myBtn(buttonPin, true,  true, 40);				// Declare the button( pin, pullup, invert, debounce ms)
      
      enum convertMode_t {channelA, channelB, channelAB} ;	// measurement modes, 32 port B / 128 port A / A & B
      
      HX711 scale;											// instantiate ADC
      
      // U8G instantiate, Change this constructor to match the display!!!
      U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);   // All Boards without Reset of the Display
      
      const int nettReadingsSize = 32 ; 						// the number of readings to determine the average and calculate variance/ accuracy
      double lastReading, lastReadingB ; 
      double nettReadings[nettReadingsSize] ; 				// store the rolling average of readings
      int nettReadingPointer = 0 ; 
      
      convertMode_t convertMode = channelA ;					// default channelA
      
      enum state_t {idleState, waitForRelease} ;      // define possible states
      static state_t state = idleState ;  
      
      
      void setup() {
      	Serial.begin(115200);
      
        Serial.println("AWI uA meter");
      
      	// u8g setup
      	u8g.begin() ;
      	u8g.setFont(u8g2_font_helvR14_tf);					// 'r' = reduced (or 'n' = numeric) font only for size
      	//u8g.setFont(u8g2_font_profont15_tf);					// 'r' = reduced (or 'n' = numeric) font only for size
      
      	// HX711.DOUT	- pin #A1
      	// HX711.PD_SCK	- pin #A0
      	// if parameter "gain" is ommited; the default value 128 is used by the library
      	//   64 & 128 is port A ; 32 is port B
      	scale.begin(HX711_dout, HX711_sck, 128); 			// set port based on state of selection
      
      	LCD_banner("Initializing") ;
      	Serial.print("read average: \t\t");
      	Serial.println(scale.read_average(20));  			// print the average of 20 raw readings from the ADC
      	
      	getOffset();										// get the offsets (drift values)
      	scale.set_offset(offsetChannelA) ;					// set it for measured channel
      	scale.set_scale(calibrationFactorA);				// this value is obtained by calibrating with known value; see the README for details
      	
      	Serial.print("read: \t\t");
      	Serial.println(scale.read());						// print a raw reading from the ADC
      	Serial.print("read average: \t\t");
      	Serial.println(scale.read_average(10));				// print the average of 20 readings from the ADC
      	Serial.print("get value: \t\t");
      	Serial.println(scale.get_value(5));					// print the average of 5 readings from the ADC minus the tare weight, set with tare()
      	Serial.print("get units: \t\t");
      	Serial.println(scale.get_units(5), 3);				// print the average of 5 readings from the ADC minus tare weight, divided by scale
      	Serial.println("Readings:");
      }
      
      void loop() {
      
      	//Serial.print("one reading:\t");
      	//Serial.print(scale.get_units(), 1);
      	//Serial.print("\t| average:\t");
      	//Serial.println(scale.get_units(30), 3);
      
        checkButton(); 
        
      	// get ADC readings dependent on setting: read A, B or A & B
      	// only A reads has average buffer when A&B mode is selected
      	if (convertMode == channelA){
      		scale.set_gain(128) ;
      		scale.set_offset(offsetChannelA) ;
      		scale.set_scale(calibrationFactorA );			// set division to A value and set mode to A
      		lastReading = scale.get_units(4) ; 			// get value (average 4 readings)corrected with scaling
      		nettReadings[nettReadingPointer] = lastReading ;	// store readings in averagebuffer
      		nettReadingPointer = (++nettReadingPointer) % nettReadingsSize ; // increment and wrap
          checkButton(); 
          LCD_local_display();
      	} else if (convertMode == channelB){
      		scale.set_gain(32) ;
      		scale.set_offset(offsetChannelB) ;
      		scale.set_scale(calibrationFactorB);			// set division to B value and set mode to B
      		lastReading = scale.get_units(4) ; 		  	// get value (average 4 readings)corrected with scaling
      		nettReadings[nettReadingPointer] = lastReading ;	// store readings in averagebuffer
      		nettReadingPointer = (++nettReadingPointer) % nettReadingsSize ; // increment and wrap
          checkButton(); 
          LCD_local_display();
      	} else if (convertMode == channelAB){				// if both channels average 128 readings iso 32 (no buffer)
      		scale.set_gain(128) ;
      		scale.set_offset(offsetChannelA) ;
      		scale.set_scale(calibrationFactorA);			// set division to A value and set mode to A
      		lastReading = scale.get_units(2) ; 		  	// get value (average 4 readings)corrected with scaling
      		checkButton(); 
      		scale.set_gain(32) ;
      		scale.set_offset(offsetChannelB) ;
      		scale.set_scale(calibrationFactorB);			// set division to A value and set mode to A
      		lastReadingB = scale.get_units(2) ; 			// get value (average 4 readings) corrected with scaling
          checkButton(); 
      		LCD_local_displayAB();
      	}
      	//scale.power_down();			       				// put the ADC in sleep mode
      	//delay(500);
      	//scale.power_up();
      	//delay(100);
      }
      
      void checkButton() { 
        
        myBtn.read();                   // read button state
        
        switch (state){
           case idleState:                  // Idle
            if (myBtn.wasPressed()) {       // Pressed 
              // change channel and wait release
              state = waitForRelease ;
            }
            break ;
          case waitForRelease:  
            if (myBtn.pressedFor(3000UL)) {  // Long Press 
               LCD_banner("Offset");
               getOffset();              
               state = idleState; 
            } else if (myBtn.wasReleased()) { // Short Press  
              state = idleState;
              switchMode() ;
            }
            break ;
          
        }
        
      }
      void LCD_banner(const char *s){
      /* prints all avaiable variables on LCD display with units
      	input: all "last" variables
      */
      	u8g.firstPage();
      	do {
      		int strWidth = u8g.getStrWidth(s) ;				// get the length of the string to determine print position
      		u8g.drawStr((128- strWidth)/2, 40, s ) ;			// print right aligned 
      	} while (u8g.nextPage()) ;
      }
      
      
      void LCD_local_display(void){
      /* prints all avaiable variables on LCD display with units
      	input: all "last" variables
      */
      	char buf[21];  										// buffer for max 20 char display
      	char lastNettBuf[14];
      	dtostrf(lastReading, 10, 2, lastNettBuf);			// Convert real to char
      	char averageNettBuf[14];
      	dtostrf(nettReadingsAverage(), 10, 2, averageNettBuf);	// Convert real to char
      	char spreadNettBuf[14];
      	dtostrf(nettReadingsSpread(), 10, 2, spreadNettBuf);	// Convert real to char
      	Serial.print("Average: \t") ; Serial.print(nettReadingsAverage());
      	Serial.print("\tSpread: \t") ; Serial.println(nettReadingsSpread());
      
      	u8g.firstPage();
      	do {
          checkButton(); 
      		snprintf(buf, sizeof buf, "Current %s", (convertMode==channelB)?"B":"A"); // Header
      		int strWidth = u8g.getStrWidth(buf) ;			//   length of the string to determine print position
      		u8g.drawStr((128- strWidth)/2, 14, buf ) ;		//   print middle aligned 
      		u8g.drawStr(0,31,"I") ;							// Current
      		snprintf(buf, sizeof buf, "%10s\xB5\A", lastNettBuf);
      		strWidth = u8g.getStrWidth(buf) ;				//   length of the string to determine print position
      		u8g.drawStr((128- strWidth), 31, buf ) ;		//   print right aligned 
      		u8g.drawStr(0,47,"avg") ;						// Average current
      		snprintf(buf, sizeof buf, "%10s\xB5\A", averageNettBuf);
      		strWidth = u8g.getStrWidth(buf) ;				// get the length of the string to determine print position
      		u8g.drawStr((128- strWidth), 47, buf ) ;		// print right aligned 
      		u8g.drawStr(0,63,"d\xB1") ;						// delta +/-
      		snprintf(buf, sizeof buf, "%10s\xB5\A", spreadNettBuf);
      		strWidth = u8g.getStrWidth(buf) ;				// get the length of the string to determine print position
      		u8g.drawStr((128- strWidth), 63, buf ) ;		// print right aligned 
      	} while (u8g.nextPage()) ;
      }
      void LCD_local_displayAB(void){
      /* prints A & B channel on LCD display with units
      	input: all "last" variables
      */
      	char buf[21];  										// buffer for max 20 char display
      	char lastNettBuf[14];
      	dtostrf(lastReading, 10, 2, lastNettBuf);			// Convert real to char
      	char lastNettBufB[14];
      	dtostrf(lastReadingB, 10, 2, lastNettBufB);			// Convert real to char
      	char lastNettBufAB[14];
      	dtostrf(lastReading +lastReadingB, 10, 2, lastNettBufAB);	// Convert real to char for added values
      	u8g.firstPage();
      	do {
          checkButton(); 
      		snprintf(buf, sizeof buf, "Current A+B"); 		// Header
      		int strWidth = u8g.getStrWidth(buf) ;			//   length of the string to determine print position
      		u8g.drawStr((128- strWidth)/2, 14, buf ) ;		//   print middle aligned 
      		u8g.drawStr(0,31,"IA");							// Current A
      		snprintf(buf, sizeof buf, "%10s\xB5\A", lastNettBuf);
      		strWidth = u8g.getStrWidth(buf) ;				//   length of the string to determine print position
      		u8g.drawStr((128- strWidth), 31, buf ) ;		//   print right aligned 
      		u8g.drawStr(0,47,"IB");							// Current B
      		snprintf(buf, sizeof buf, "%10s\xB5\A", lastNettBufB);
      		strWidth = u8g.getStrWidth(buf) ;				//   length of the string to determine print position
      		u8g.drawStr((128- strWidth), 47, buf ) ;		//   print right aligned 
      		u8g.drawStr(0,63,"A+B");						// Current A + B
      		snprintf(buf, sizeof buf, "%10s\xB5\A", lastNettBufAB);
      		strWidth = u8g.getStrWidth(buf) ;				//   length of the string to determine print position
      		u8g.drawStr((128- strWidth), 63, buf ) ;		//   print right aligned 
      	} while (u8g.nextPage()) ;
      }
      
      // calculate average of nett readings
      double nettReadingsAverage() {
      	double sum = 0;
      	for (byte i = 0; i < nettReadingsSize; i++) {
      		sum += nettReadings[ i ];
      	}
      	return sum / nettReadingsSize;
      }
      
      // calculate spread of nett readings (+/-)
      double nettReadingsSpread() {
      	double minReading = nettReadings[0];
      	double maxReading = minReading ;
      	for (byte i = 1; i < nettReadingsSize; i++) {
          checkButton(); 
      		if (minReading > nettReadings[ i ]){
      			minReading = nettReadings[i] ;
      		}
      		if (maxReading < nettReadings[ i ]){
      			maxReading = nettReadings[i] ; 
      		}
      	}
      	return (maxReading - minReading)/2 ;
      }
      
      // switch the mode
      void switchMode(){
      	if (convertMode == channelA){
      		convertMode = channelB ;
      	} else if (convertMode == channelB){
      		convertMode = channelAB ;
      	} else {
      		convertMode = channelA ;
      	}
      }
      
      // assuming both channels are shorted, calculate the offset values for channel A and B
      double getOffset(){
      	scale.set_gain(128) ;							// get channel A
      	offsetChannelA = scale.read_average(32) ;		// average 512 readings for offset
      	Serial.print("Offset A: \t") ; 
      	Serial.println(offsetChannelA);
      	scale.set_gain(32) ;							// get channel B
      	offsetChannelB = scale.read_average(32) ;		// average 512 readings for offset
      	Serial.print("Offset B: \t") ; 
      	Serial.println(offsetChannelB);
      }```
      posted in OpenHardware.io
      rvendrame
      rvendrame
    • RE: Wired instead of wireless sensors; How To?

      @MaxG , maybe this may help a bit.

      posted in General Discussion
      rvendrame
      rvendrame
    • RE: Newbie Problem! Get Started with NRF24L01+

      @fakeJake said:

      > Incoming change for sensor:0
      

      Means your are asking to activate relay 'zero'.

      digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
      

      So digital pin will be 0 - 1 + RELAY_1 = 0 - 1 + 3 = 2

      Conclusion: Try activating relay 1 instead 0. 😉

      posted in Development
      rvendrame
      rvendrame
    • RE: MH-Z14A CO2 senso

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

      posted in Hardware
      rvendrame
      rvendrame
    • RE: Inventory webpage

      @Nca78 Agree. But I liked the idea of a simple text search, where you enter for example 'MOSFET' and it lights up all bins with mosfets ... It is now in my list 'projects to investigate after finishing all ongoing' 😉

      posted in General Discussion
      rvendrame
      rvendrame
    • RE: Newbie Problem! Get Started with NRF24L01+

      Just swap the 0 & 1 here:

      #define RELAY_ON 1  // GPIO value to write to turn on attached relay
      #define RELAY_OFF 0 // GPIO value to write to turn off attached relay
      

      and it will obey as you expect. Some relays boards have inverted input (Zero/GND is ON and VCC is OFF) 😉

      I'm glad it worked.

      posted in Development
      rvendrame
      rvendrame
    • RE: Water level measurement - Ultrasonics V Pressure

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

      posted in Hardware
      rvendrame
      rvendrame
    • RE: Modifying A0 value to Percentage

      @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...

      posted in General Discussion
      rvendrame
      rvendrame
    • RE: Help with sleeping door sensor

      @ustredna , try changing this line:

      send(msg.set(value==HIGH));

      by

      send(msg.set(value));

      The same for msg2 line:

      send(msg2.set(value==HIGH));

      to

      send(msg2.set(value));

      And if you only need to update the GW on every 7 seconds (and not immediately), change the sleep:

      sleep( 7000 ) ;

      Hope it helps!

      posted in Development
      rvendrame
      rvendrame
    • RE: Modifying A0 value to Percentage

      @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  ));
      
      posted in General Discussion
      rvendrame
      rvendrame
    • RE: Merge Help: Door+ BME280

      @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..
          {
          }
        }  
      }
      
      posted in Development
      rvendrame
      rvendrame
    • RE: Combining a motion sensor with an led on one node

      @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
      
      posted in Development
      rvendrame
      rvendrame