Navigation

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

    Posts made by Ben Andrewes

    • RE: custom variable to domoticz to trigger scripts then reset...

      Cheers @gohan - I solved it in the end:

      First tried to set as a text sensor but changing the text on a sensor doesn't trigger an event in Domoticz (or at least I couldn't make it happen). Instead I present it as a light level sensor which can be used and is hidden away on a different tab in Domoticz....

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: Unable to get relay status from Domoticz

      You could try editing out all the ifs etc in the getStateFromController and only request the state (surrounded by a few serial prints to see which bits execute). If it works in simplest form then you could build up the logic around it to see what is failing

      void getStateFromController() {
      
        Serial.println(" starting GetStateFromController");
        request( CHILD_ID_RELAY , V_STATUS);
        wait (WAIT_RETURN);
       serial.print("Waiting");
      
      }    
      
      
      posted in Development
      Ben Andrewes
      Ben Andrewes
    • custom variable to domoticz to trigger scripts then reset...

      I have a gesture sensor incorporated into a node that I want to use to trigger logic scripts in Domoticz.

      There are 6 possible gestures (up, down, left, right, near,far). Currently I have presented it as 3 binary switches:

      1. GestureUpDown, S_Binary, gesture up turns on switch, gesture down turns off switch
      2. GestdureLeftRight, S_Binary, left = on, right = off
      3. GestureNearFar, S_Binary, near=on, far = off.

      The problem is that some of the events it will trigger are not binary e.g. I want to link the up/down to my kitchen light that has 3 settings (Off, On 50%,, On 100%). So I'd like to gesture up and then Domoticz will check current light setting and increment up one step e.g. if it is off then it will switch to 50%, if it is already at 50% then it will increase to 100%, and the opposite with downward gestures.

      I am fine getting this to work on a single iteration, but the problem is that once I have swiped up once then Domoticz regards the GestureUpDown switch as already on so doesn't trigger any event as the switch state hasn't changed.

      What I'd like to do is have the 6 gestures report to Domoticz as e.g. integers 1,2,3,4,5,6 which will then trigger an event and subsequently Domoticz will reset the sensor that it is linked to back to 0. Then every time I e.g. swipe up, it will trigger the script.

      I am having trouble working out what sensor to present this as - I could present it as a Dimmer switch so that the gestures set the dimmer at e.g. 10%...60% but it feels like a bit of a bodge. I also thought about presented it as 6 separate V_TRIPPED sensors but it feels messy. I'm also finding that the switches tab in Domoticz is becoming full of random switches that aren't really switches if you know what I mean!

      Anyone got any ideas of a nice workaround?

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • Switch with 3 settings - domoticz

      I am trying to create a switch that has 3 states but am unsure what to present it as. It will be used to send a setting, that can be one of 3 things, to the node.

      What I'd like is a simple selector switch in Domoticz which has 3 buttons and if button 1 is pressed it sends e.g. value1 to the node (which will then change a setting within the node).

      I have tried presenting an S_Custom child with V_VAR1 as the message but nothing shows in Domoticz.

      Am I missing an obvious solution?

      posted in General Discussion
      Ben Andrewes
      Ben Andrewes
    • RE: MultiSensor - relays, temp, hum, PIR, gesture with various controller overrides

      @dbemowsk Just looked at your weather station - ace work.

      I was intrigued by this:

      #ifdef  DEBUG_ON
        #define DEBUG_PRINT(x)   Serial.print(x)
        #define DEBUG_PRINTLN(x) Serial.println(x)
        #define SERIAL_START(x)  Serial.begin(x)
        #else
        #define DEBUG_PRINT(x)
        #define DEBUG_PRINTLN(x)
        #define SERIAL_START(x)
      #endif
      

      I think I understand that if DEBUG_ON is defined then wherever you have e.g.
      DEBUG_PRINT("Hello")
      The compiler will turn this into serial.print("Hello")

      My question is what happens if DEBUG_ON is not defined? How does the compiler treat lines such as DEBUG_PRINT("Hello")?

      Is it that because in the #else part DEBUG_PRINT is defined but not actually defined as anything then the compiler will delete the DEBUG_PRINT("Hello") completely?

      Sorry for all the questions but I am trying to get my head around compiling vs programming and then how I can use it to make things more efficient...

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: MultiSensor - relays, temp, hum, PIR, gesture with various controller overrides

      @dbemowsk with all the Serialprints & debugs etc defined, it is 78% of program storage & 65% of variable storage but importantly no warnings from the IDE that memory is low

      if I comment out all of the defines then it is 49% & 59%. Good result either way.

      One thing that I'd like to do is to call separate subroutines for e.g. firstboot but I had all sorts of strange results when I didn't just include it in the main loop(). I think this might be because the loop is still, um, looping while these subroutines run - do you think I am right in thinking this is the problem? If so, is there a way around it?

      Cheers

      Ben

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: Prevent Relay from triggering on power loss or broker reboot

      @rhuehn I know this is an old post but I had a similar issue which I solved by inserting a line in my sketch to pull the pin high before setting it as output

        digitalWrite(RELAY_1_PIN , HIGH);  //stops relays cycling state during boot
        digitalWrite(RELAY_2_PIN , HIGH);  //stops relays cycling state during boot
        
        pinMode(RELAY_1_PIN , OUTPUT);
        pinMode(RELAY_2_PIN , OUTPUT);
      
      posted in Troubleshooting
      Ben Andrewes
      Ben Andrewes
    • RE: MultiSensor - relays, temp, hum, PIR, gesture with various controller overrides

      I've put the updated code below in case it is useful to anyone..

      I also found that the relays were switching on and off during first boot which was a pain, again my solution is below (I couldn't find a reference to this problem in the forums). As the relays are active low, I set the relay pins to high before setting them as outputs

        digitalWrite(RELAY_1_PIN , HIGH);  //stops relays cycling state during boot
        digitalWrite(RELAY_2_PIN , HIGH);  //stops relays cycling state during boot
        
        pinMode(RELAY_1_PIN , OUTPUT);
        pinMode(RELAY_2_PIN , OUTPUT);
      
      /**
         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.
      
       *******************************
      
      Hardware Connections:
      
      IMPORTANT: The APDS-9960 can only accept 3.3V!
       
       Arduino Pin  APDS-9960 Board  Function
       
       3.3V         VCC              Power
       GND          GND              Ground
       A4           SDA              I2C Data
       A5           SCL              I2C Clock
       2            INT              Interrupt
      */
      
      // Enable debug prints to serial monitor
      // #define MY_DEBUG //mysensors protocol debug prints
      // #define SerialPrints //all the verbose messages that state what the program is doing at certain points e.g. "Requesting message from Domoticz"
      // #define ImAlive  // Heartbeat in main loop
      #define SerialReadings  //Sensor readings e.g. temp and certain messages from Domoticz e.g. if turning a relay on
      
      // Enable and select radio type attached
      #define MY_RADIO_NRF24
      //#define MY_RADIO_RFM69
      
      // Enable repeater functionality for this node
      #define MY_REPEATER_FEATURE
      #define MY_NODE_ID 103
      
      #include <Wire.h>
      #include <SparkFun_APDS9960.h>
      #include <SPI.h>
      #include <DHT.h>
      #include <MySensors.h>
      
      #define RELAY_1_PIN  5  // Arduino Digital I/O pin number for first relay 
      #define RELAY_2_PIN  6  // Arduino Digital I/O pin number for second relay 
      
      #define RELAY_ON 0  // GPIO value to write to turn on attached relay - domoticz needs 0 for on, 1 for off
      #define RELAY_OFF 1 // GPIO value to write to turn off attached relay
      
      
      #define CHILD_ID_RELAY1 1
      #define CHILD_ID_RELAY2 2
      #define CHILD_ID_HUM 3
      #define CHILD_ID_TEMP 4
      #define CHILD_ID_MOT 5   // Id of the sensor child
      #define CHILD_ID_TEMP_OFFSET 20
      #define CHILD_ID_MotionOnOff 21
      #define CHILD_ID_GESTUREUD 30  //up down gesture
      #define CHILD_ID_GESTURELR 31 //left right gesture
      #define CHILD_ID_GESTURENF 32 //near far gesture
      #define GestureUp 1 //command to send on gesture, 0 = off, 1 = on
      #define GestureDown 0 //command to send on gesture, 0 = off, 1 = on
      #define GestureLeft 0 //command to send on gesture, 0 = off, 1 = on
      #define GestureRight 1 //command to send on gesture, 0 = off, 1 = on
      #define GestureNear 0 //command to send on gesture, 0 = off, 1 = on
      #define GestureFar 1 //command to send on gesture, 0 = off, 1 = on
      #define GestureSensitivity  0  // value between 0 & 3, 0 most sensitive, 3 least
      
      
      #define HUMIDITY_SENSOR_DIGITAL_PIN 7
      
      #define APDS9960_INT    2  // for the APDS-9960 - Needs to be an interrupt pin
      
      #define DIGITAL_INPUT_SENSOR 3   // The digital input you attached your motion sensor.  (Only 2 and 3 generates interrupt!)
      #define INTERRUPT DIGITAL_INPUT_SENSOR-2 // for the PIR - Usually the interrupt = pin -2 (on uno/nano anyway)
      
      SparkFun_APDS9960 apds = SparkFun_APDS9960();
      volatile int isr_flag = 0; //handles the interrupt process for gesture sensor
      
      
      
      
      unsigned long SLEEP_TIME = 120000; // Sleep time between reads of temp/hum (in milliseconds)
      unsigned long lastRefreshTime = 0; // Use this to implement a non-blocking delay function
      unsigned long RefreshCyclesUntilForcedUpdate = 5; // use to force a temp/hum reading after 'n' SLEEP_TIME cycles even if value hasn't changed, set v.high (e.g. 10,000) to effectively disable
      unsigned long ForceUpdate = RefreshCyclesUntilForcedUpdate * SLEEP_TIME; // Force update read after this amount of time
      unsigned long lastForceUpdateTime = 0; // Use this to implement a non-blocking delay function that forces update even if temp hasn't changed
      
      DHT dht;
      float lastTemp;
      float lastHum;
      
      boolean metric = true;
      
      bool lastTripped = 0;   // Used to store last motion sensor value
      boolean FirstBoot = true;
      
      // the below allow you decide if the default state of certain sensors is stored in EEPROM or Controller or always start in a certain state
      // 1 = EEPROM 2 = Controller (e.g. Domoticz), 3 or any other number then they start as with default values
      // If option 1 or 3 is selected then we will also send a message to the controller to tell it the states
      
      // unsigned long WaitBetweenSendingMessages = 150; //how long to wait between sending messages and presenting nodes
      int StoreTempOffset = 2;
      int StoreMotionOnOff = 2;
      int StoreRelayState = 2;
      
      // below are the default states that you can set to be loaded at boot each time
      // these will be reverted to in EEPROM values are corrupted
      bool MotionON = 0;      //enable/disable the PIR reports (1=enabled 0=disabled)
      bool RelayState = 0;    // default state for relays (1 = on, 0 = off)
      
      int TempOffset = 50; // a value of 50 means that initial offset is zero when first loaded.  Tempoffset can be between 0-100
      volatile float ActualTempOffset = (TempOffset / 10.0) - 5.0;  //Adjust temp offset to a decimal between +/- 5 degrees
      
      MyMessage msgHum(CHILD_ID_HUM, V_HUM);
      MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
      MyMessage msgMot(CHILD_ID_MOT, V_TRIPPED);
      MyMessage msgTempOffset(CHILD_ID_TEMP_OFFSET, V_PERCENTAGE);
      MyMessage msgMotOnOff(CHILD_ID_MotionOnOff, V_STATUS);
      MyMessage msgRelay1(1, V_STATUS);
      MyMessage msgRelay2(2, V_STATUS);
      MyMessage msgGestureUpDown(CHILD_ID_GESTUREUD, V_STATUS);
      MyMessage msgGestureLeftRight(CHILD_ID_GESTURELR, V_STATUS);
      MyMessage msgGestureNearFar(CHILD_ID_GESTURENF, V_STATUS);
      
      void before()
      {
      
        // Then set relay pins in output mode
        digitalWrite(RELAY_1_PIN , HIGH);
        digitalWrite(RELAY_2_PIN , HIGH);
        
        pinMode(RELAY_1_PIN , OUTPUT);
        pinMode(RELAY_2_PIN , OUTPUT);
        
      
        
        pinMode(DIGITAL_INPUT_SENSOR, INPUT);      // sets the motion sensor digital pin as input
      
      
      
      
      }
      
      void setup()
      {
        // Set gesture sensor interrupt pin as input
        pinMode(APDS9960_INT, INPUT);
          
          //define sensitivity of gesture sensor
          apds.setGestureGain( GestureSensitivity );
        
        dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
        // metric = getConfig().isMetric;
      
        // Initialize interrupt service routine for gestures
        
       attachInterrupt(digitalPinToInterrupt(APDS9960_INT), interruptRoutine, FALLING);
      
      
        // Initialize APDS-9960 (configure I2C and initial values)
      //Do not get rid of these if statements as they initialise the gesture sensing 
        if ( apds.init() ) {
          Serial.println(F("APDS-9960 initialization complete"));
        } else {
          Serial.println(F("Something went wrong during APDS-9960 init!"));
        }
      
        
        // Start running the APDS-9960 gesture sensor engine
        if ( apds.enableGestureSensor(true) ) {
          Serial.println(F("Gesture sensor is now running"));
        } else {
          Serial.println(F("Something went wrong during gesture sensor init!"));
        }
      
      }
      
      void presentation()
      {
        // Send the sketch version information to the gateway and Controller
        sendSketchInfo("MyMultiSensor", "1.4");
      
      
        // Register all sensors to gw (they will be created as child devices)
        present(CHILD_ID_RELAY1, S_BINARY, "Relay 1");
        wait(100);
        present(CHILD_ID_RELAY2, S_BINARY, "Relay 2");
        wait(100);
        present(CHILD_ID_HUM, S_HUM, "Humidity");
        wait(100);
        present(CHILD_ID_TEMP, S_TEMP, "Temperature");
        wait(100);
        present(CHILD_ID_MOT, S_MOTION, "PIR");
        wait(100);
        present(CHILD_ID_TEMP_OFFSET, S_DIMMER, "Temp Calibration");
        wait(100);
        present(CHILD_ID_MotionOnOff, S_BINARY, "PIR Enable/Disable");
        wait(100);
        present(CHILD_ID_GESTUREUD, S_BINARY, "Gesture Up/Down");
        wait(100);
        present(CHILD_ID_GESTURELR, S_BINARY, "Gesture Left/Right");
        wait(100);
        present(CHILD_ID_GESTURENF, S_BINARY, "Gesture Near/Far");
        wait(100);  
       
      }
      
      void firstboot()
      {
        
        }
        
        
      void loop()
      {
        if(FirstBoot)
        {
      #ifdef SerialPrints
        Serial.println(F("FirstBoot sequence started"));
      #endif
        // Set relay to correct state (using eeprom/default/domoticz value)
        switch (StoreRelayState) {
          case 1:
            if (loadState(CHILD_ID_RELAY1) == 1)  {
              digitalWrite(RELAY_1_PIN , RELAY_ON);  
            }
            else
            {
              digitalWrite(RELAY_1_PIN , RELAY_OFF);  
            }
            if (loadState(CHILD_ID_RELAY2) == 1)  {
              digitalWrite(RELAY_2_PIN , RELAY_ON);  
            }
            else
            {
              digitalWrite(RELAY_2_PIN , RELAY_OFF);  
            }
      
            #ifdef SerialPrints
              Serial.print(F("Relay 1 loadstate from EEPROM: "));
              Serial.println(loadState(CHILD_ID_RELAY1));
              Serial.print(F("Relay 2 loadstate from EEPROM: "));
              Serial.println(loadState(CHILD_ID_RELAY2));
            #endif
              //best let domoticz know
              send(msgRelay1.set(RelayState));
              wait(100);
              send(msgRelay2.set(RelayState));
              wait(100);
      
            #ifdef SerialPrints
              Serial.print(F("Default Relay state sent to Domoticz: "));
              Serial.println(RelayState);
            #endif
          break;
            
          case 2: 
              //get Relay Statuses from Domoticz
              #ifdef SerialPrints          
                Serial.println(F("Relay status requested from Domoticz"));          
              #endif
                request(CHILD_ID_RELAY1, V_STATUS);
                wait(1000);
                request(CHILD_ID_RELAY2, V_STATUS);
                wait(1000);
                
          break;
          default:
              digitalWrite(RELAY_1_PIN ,  RelayState ? RELAY_ON : RELAY_OFF);
              digitalWrite(RELAY_2_PIN ,  RelayState ? RELAY_ON : RELAY_OFF);
            #ifdef SerialPrints        
              Serial.print(F("Relays set to default boot state: "));
              Serial.println(RelayState);
            #endif
              send(msgRelay1.set(RelayState));
              wait(100);
              send(msgRelay2.set(RelayState));
              wait(100);
            #ifdef SerialPrints
              Serial.print(F("Default Relay state sent to Domoticz: "));
              Serial.println(RelayState);
            #endif
          break;
          }
        
        // Set tempoffset to correct state (using eeprom/default/domoticz value) - needs to be 0 - 100 otherwise set to no offset
      
          switch (StoreTempOffset)  {
            case 1:
              if (loadState(CHILD_ID_TEMP_OFFSET) >100) {
                ActualTempOffset = 5.0;
              }
              else
              {
                TempOffset = loadState(CHILD_ID_TEMP_OFFSET);
                ActualTempOffset = (TempOffset / 10.0) - 5.0;
              }
              #ifdef SerialPrints
                Serial.print(F("Temp Offset retrieved from eeprom: "));
                Serial.println(ActualTempOffset);
              #endif
                //let Domoticz know the value
                send(msgTempOffset.set(TempOffset, 1));
                wait(100);
              #ifdef SerialPrints
                Serial.print(F("tempOffset from sensor sent to Domoticz: "));
                Serial.println(TempOffset);
              #endif
            break;
            case 2:
              //get TempOffSet from Domoticz 
              #ifdef SerialPrints
                Serial.println(F("TempOffset value requested from Domoticz"));         
              #endif
                request(CHILD_ID_TEMP_OFFSET, V_PERCENTAGE);
                wait(1000);
                
            break;
            default:
              #ifdef SerialPrints
                Serial.print(F("Default boot temperature offset is: "));
                Serial.println(ActualTempOffset);
              #endif
                //let Domoticz know the value
                send(msgTempOffset.set(TempOffset, 1));
                wait(100);
              #ifdef SerialPrints
                Serial.print(F("tempOffset from sensor sent to Domoticz: "));
                Serial.println(TempOffset);    
              #endif
            break;
          }
      
          // Set PIR enable/disable (using eeprom/default/domoticz value)  
          switch(StoreMotionOnOff) {
            case 1:
              if (loadState(CHILD_ID_MotionOnOff) == 1 || loadState(CHILD_ID_MotionOnOff) == 0) { //check for odd values in EEPROM
                MotionON = loadState(CHILD_ID_MotionOnOff);  
              }
              else {
              #ifdef SerialPrints
                Serial.print(F("Error in PIR Enable/Disable Value in EEPROM"));
                Serial.println(F("Default value used instead"));
              #endif
              } 
              //Let Domoticz know
                send(msgMotOnOff.set(MotionON, 1));
                wait(100);
              #ifdef SerialPrints  
                Serial.print(F("PIR ENABLE status from sensor sent to Domoticz: "));
                Serial.println(MotionON);  
              #endif  
            break;
             
            case 2:
              //get PIR enable status from Domoticz
              #ifdef SerialPrints
                Serial.println(F("MotionOnOff status requested from Domoticz"));          
              #endif
                request(CHILD_ID_MotionOnOff, V_STATUS);
                wait(1000);
      
      
            break;
                
      
            default:
                send(msgMotOnOff.set(MotionON, 1));
                wait(100);
              #ifdef SerialPrints
                Serial.print(F("Default PIR ENABLE status used and sent to Domoticz: "));
                Serial.println(MotionON); 
              #endif
            break;
          }
        wait(2000);
      #ifdef SerialPrints
        Serial.println("First boot checks completed");
      #endif 
        #ifdef ImAlive
          Serial.println(F("I'm alive"));
        #endif 
        FirstBoot = false;
        }
      
        //check if gesture sensor interrupt is triggered
          if( isr_flag == 1 ) {
          detachInterrupt(digitalPinToInterrupt(APDS9960_INT));
          handleGesture();
          isr_flag = 0;
          attachInterrupt(digitalPinToInterrupt(APDS9960_INT), interruptRoutine, FALLING);
      
        }
        
        // Read digital motion value
        if (MotionON) {
          bool tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH;
          if (lastTripped != tripped) {
          #ifdef SerialReadings
            Serial.print(F("New Motion State: "));
            Serial.println(tripped);
          #endif
            // Send tripped value to gw
            send(msgMot.set(tripped ? "1" : "0"));
            lastTripped = tripped;
          }
        }
      
      
      
        boolean needRefresh = (millis() - lastRefreshTime) > SLEEP_TIME;
        if (needRefresh)
        {
        #ifdef ImAlive
          Serial.println(F("I'm alive"));
        #endif
          lastRefreshTime = millis();
      
          float temperature = dht.getTemperature() + ActualTempOffset;
          if (isnan(temperature)) {
          #ifdef SerialReadings
            Serial.println(F("Failed reading temperature from DHT"));
          #endif
          }
          else if (temperature != lastTemp  ) {
            lastTemp = temperature;
            if (!metric) {
              temperature = dht.toFahrenheit(temperature);
            }
            send(msgTemp.set(temperature, 1));
          #ifdef SerialReadings
            Serial.print(F("T: "));
            Serial.println(temperature);
          #endif
          }
          else if (millis() - lastForceUpdateTime > ForceUpdate) {
            lastTemp = temperature;
            lastForceUpdateTime = millis();
            if (!metric) {
              temperature = dht.toFahrenheit(temperature);
            }
            send(msgTemp.set(temperature, 1));
          #ifdef SerialReadings
            Serial.print("T: ");
            Serial.println(temperature);
          #endif
          }
      
      
          float humidity = dht.getHumidity();
          if (isnan(humidity)) {
          #ifdef SerialReadings
            Serial.println(F("Failed reading humidity from DHT"));
          #endif
          }
          else if (humidity != lastHum) {
            lastHum = humidity;
            send(msgHum.set(humidity, 1));
          #ifdef SerialReadings  
            Serial.print(F("H: "));
            Serial.println(humidity);
          #endif
          }
          else if (millis() - lastForceUpdateTime > ForceUpdate) {
            lastHum = humidity;
            lastForceUpdateTime = millis();
            send(msgHum.set(humidity, 1));
          #ifdef SerialReadings
            Serial.print(F("H: "));
            Serial.println(humidity);
          #endif
          }
        }
      
      }
      
      void interruptRoutine() {
      #ifdef SerialPrints  
        Serial.println("Interrupt Routine started");
      #endif
        isr_flag = 1;
      }
      
      void handleGesture() {
      
       
        
          if ( apds.isGestureAvailable() ) {
      
      
          switch ( apds.readGesture() ) {
            case DIR_UP:
            #ifdef SerialReadings
              Serial.println(F("UP"));
            #endif
              send(msgGestureUpDown.set(GestureUp));
              break;
            case DIR_DOWN:
            #ifdef SerialReadings
              Serial.println(F("DOWN"));
            #endif
              send(msgGestureUpDown.set(GestureDown));
              break;
            case DIR_LEFT:
            #ifdef SerialReadings
              Serial.println(F("LEFT"));
            #endif
              send(msgGestureLeftRight.set(GestureLeft));
              break;
            case DIR_RIGHT:
            #ifdef SerialReadings
              Serial.println(F("RIGHT"));
            #endif
              send(msgGestureLeftRight.set(GestureRight));
              break;
            case DIR_NEAR:
            #ifdef SerialReadings
              Serial.println(F("NEAR"));
            #endif
              send(msgGestureNearFar.set(GestureNear));
              break;
            case DIR_FAR:
            #ifdef SerialReadings
              Serial.println(F("FAR"));
            #endif
              send(msgGestureNearFar.set(GestureFar));
              break;
            default:
            #ifdef SerialReadings
              Serial.println(F("NONE"));
            #endif
            break;
          }
        
         }
        
      }
      
      void receive(const MyMessage &message)
      {
       //For debugging just checking why controller sent a msg e.g. was it in response to a request by node  
      #ifdef SerialPrints
        switch (message.getCommand()) {                                 // message.getCommand will give us the command type of the incomming message
            case C_SET: 
              Serial.println(F("msg sent by controller"));
            break;
            case C_REQ:
              Serial.println(F("msg state sent by controller in response to request"));
            break;
            default:
              Serial.println(F("msg isn't C_SET or C_REQ so what you gonna do?"));
            break;
        }
      #endif
        // We only expect V_STATUS (for relays) or V_Percentage (for temp offset) message from controller. But we better check anyway.
        if (message.type == V_STATUS) {
          // Change relay state
      
          if (message.sensor == 1 ) {
            
            digitalWrite(RELAY_1_PIN , message.getBool() ? RELAY_ON : RELAY_OFF);
            // Store state in eeprom
            saveState(message.sensor, message.getBool());
            // Write some debug info
          #ifdef SerialReadings
            Serial.print(F("Incoming Relay 1 State: "));
            Serial.println(message.getBool());
          #endif
          }
          else if (message.sensor == 2) {
           
            digitalWrite(RELAY_2_PIN , message.getBool() ? RELAY_ON : RELAY_OFF);
            // Store state in eeprom
            saveState(message.sensor, message.getBool());
            // Write some debug info
          #ifdef SerialReadings
            Serial.print(F("Incoming Relay 2 State: "));
            Serial.println(message.getBool());
          #endif
          }
          else if (message.sensor == CHILD_ID_MotionOnOff) {
      
              if (message.getBool() == 1) {
                MotionON = 1;
                saveState(CHILD_ID_MotionOnOff, MotionON);
              }
              else
              {
                MotionON = 0;
              }
              #ifdef SerialReadings
                Serial.print(F("Motion Sensor on/off state from Domoticz: "));
                Serial.println(MotionON);
              #endif
                saveState(CHILD_ID_MotionOnOff, MotionON);
          
          }
        }
        else if (message.type == V_PERCENTAGE)  {
          int TempOffset = atoi(message.data);
          ActualTempOffset = (TempOffset / 10.0) - 5.0;
        #ifdef SerialReadings
          Serial.print(F("Temp Offset value from Domoticz: "));
          Serial.println(ActualTempOffset);
          saveState(CHILD_ID_TEMP_OFFSET, TempOffset);
        #endif
        }
        
      
      }
      
      
      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: MultiSensor - relays, temp, hum, PIR, gesture with various controller overrides

      @BulldogLowell I didn't even notice the F() thing as I copied that bit of code from the sparkfun example. Thanks for the pointer though - I've update all the Serialprints to include it.

      I guess that I am so used to not even thinking about memory limits with the GB of mem in everyday device that it hadn't even crossed my mind that I could (and should) choose where to store stuff. 30 yrs ago with my Spectrum 48k it was something to be careful of... The pro mini has almost the same amount memory!

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: MultiSensor - relays, temp, hum, PIR, gesture with various controller overrides

      Thanks for the help , much appreciated. I added 3 #defines so I have a bit of control over what gets cut out i.e. the verbose stuff is really only useful at development stage but I guess if I start getting weird sensor readings then it will be helpful to have a serial reading of what the sensors are reporting. If I comment out all 4 defines then I use less than half the available memory

      #define MY_DEBUG //mysensors protocol debug prints
      #define SerialPrints //all the verbose messages that state what the program is doing at certain points e.g. "Requesting message from Domoticz"
      #define ImAlive  // Heartbeat in main loop
      #define SerialReadings  //Sensor readings e.g. temp and certain messages from Domoticz e.g. if turning a relay on
      

      I might be starting to get a bit of an idea of how this stuff works... 🙂

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: MultiSensor - relays, temp, hum, PIR, gesture with various controller overrides

      @dbemowsk Sounds like a good idea, but I'm not sure how... does that mean I'd do something like

      #define serialmessages

      then around each Serial.print

      do some sort of if clause?

      Thanks in advance for any advice

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • MultiSensor - relays, temp, hum, PIR, gesture with various controller overrides

      This is my first real effort at making a sensor... It is also my first time programming Arduinos - I learnt BASIC at school 30yrs ago and use VBA at work but that is it so be kind please... 🙂 I am grateful for any suggestions on how to improve it and cut out any lines I don't need

      I already use RFLink and Domoticz to do some controlling around my house but with MySensors I thought I could add to that. The aim is to create one lot of code that can then be used on about 10 separate idenitcal nodes around the house. That way I can debug the code before deployment rather than having to debug every node.

      I decided I needed temp, humidity, a couple of relays, a PIR, and (on a whim) a gesture sensor. I used a dht11 for the temp/hum and apds-9960 for the gestures. I wanted lots of possibilities for sending command to Domoticz which will then handle the logic e.g. using the gesture sensor, if I swipe up I'll get Domoticz to switch on a relay.

      I've also made it so that there is a separate switch that can deactivate motion sensing from the controller (don't know why, just seemed like a good idea. In addition I made a temperature adjustment child by declaring a dimmer switch then using the value to calculate an adjustment where 50% dimmed is 0 degrees offset. 0% = -5 degrees, 25% = -2.5 degrees, 50% = no offset, 75% = +2.5 degrees, 76% = +2.6 degrees etc.

      Fianlly I thought that dealing with the status of the relays, the PIR, and temp offset might be different depending on the sensor (e.g. I might want a relay connected to a fridge to default to "On" if the node rebooted for any reason, but e.g. the light in the garage to default to off, I might also want the sensor to get the last value from eeprom as in the relay example sketch or even query Domoticz to find the current state according to it).

      To do this I added a StoreXState variable that can be 1,2, or 3 and after a power cycle, it decides if the "Motion Enable/disable", Relays, & Temp Offset states are either default, got from EEPROM, or requested from Domoticz.

      I'm pretty pleased with it as a first attempt, so thought I'd share the code. A few things:

      • there are loads of Serial Prints so I could see what was happening
      • if debug is defined then it uses loads of memory (like 99%) on a pro mini and I got really odd behaviour from the node
      • I've borrowed heavily from other people's code, thank you to them
      • it is currently a jumble of wires on my desk so no pics yet
      • massive thanks to the MySensors team
      /**
         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.
      
       *******************************
      
      Hardware Connections:
      
      IMPORTANT: The APDS-9960 can only accept 3.3V!
       
       Arduino Pin  APDS-9960 Board  Function
       
       3.3V         VCC              Power
       GND          GND              Ground
       A4           SDA              I2C Data
       A5           SCL              I2C Clock
       2            INT              Interrupt
      */
      
      // Enable debug prints to serial monitor
      //#define MY_DEBUG
      
      // Enable and select radio type attached
      #define MY_RADIO_NRF24
      //#define MY_RADIO_RFM69
      
      // Enable repeater functionality for this node
      #define MY_REPEATER_FEATURE
      #define MY_NODE_ID 103
      
      #include <Wire.h>
      #include <SparkFun_APDS9960.h>
      #include <SPI.h>
      #include <DHT.h>
      #include <MySensors.h>
      
      #define RELAY_1_PIN  5  // Arduino Digital I/O pin number for first relay 
      #define RELAY_2_PIN  6  // Arduino Digital I/O pin number for second relay 
      
      #define RELAY_ON 0  // GPIO value to write to turn on attached relay - domoticz needs 0 for on, 1 for off
      #define RELAY_OFF 1 // GPIO value to write to turn off attached relay
      
      
      #define CHILD_ID_RELAY1 1
      #define CHILD_ID_RELAY2 2
      #define CHILD_ID_HUM 3
      #define CHILD_ID_TEMP 4
      #define CHILD_ID_MOT 5   // Id of the sensor child
      #define CHILD_ID_TEMP_OFFSET 20
      #define CHILD_ID_MotionOnOff 21
      #define CHILD_ID_GESTUREUD 30  //up down gesture
      #define CHILD_ID_GESTURELR 31 //left right gesture
      #define CHILD_ID_GESTURENF 32 //near far gesture
      #define GestureUp 1 //command to send on gesture, 0 = off, 1 = on
      #define GestureDown 0 //command to send on gesture, 0 = off, 1 = on
      #define GestureLeft 0 //command to send on gesture, 0 = off, 1 = on
      #define GestureRight 1 //command to send on gesture, 0 = off, 1 = on
      #define GestureNear 0 //command to send on gesture, 0 = off, 1 = on
      #define GestureFar 1 //command to send on gesture, 0 = off, 1 = on
      #define GestureSensitivity  0  // value between 0 & 3, 0 most sensitive, 3 least
      
      
      #define HUMIDITY_SENSOR_DIGITAL_PIN 7
      
      #define APDS9960_INT    2  // for the APDS-9960 - Needs to be an interrupt pin
      
      #define DIGITAL_INPUT_SENSOR 3   // The digital input you attached your motion sensor.  (Only 2 and 3 generates interrupt!)
      #define INTERRUPT DIGITAL_INPUT_SENSOR-2 // for the PIR - Usually the interrupt = pin -2 (on uno/nano anyway)
      
      SparkFun_APDS9960 apds = SparkFun_APDS9960();
      volatile int isr_flag = 0; //handles the interrupt process for gesture sensor
      
      
      
      
      unsigned long SLEEP_TIME = 120000; // Sleep time between reads of temp/hum (in milliseconds)
      unsigned long lastRefreshTime = 0; // Use this to implement a non-blocking delay function
      unsigned long RefreshCyclesUntilForcedUpdate = 5; // use to force a temp/hum reading after 'n' SLEEP_TIME cycles even if value hasn't changed, set v.high (e.g. 10,000) to effectively disable
      unsigned long ForceUpdate = RefreshCyclesUntilForcedUpdate * SLEEP_TIME; // Force update read after this amount of time
      unsigned long lastForceUpdateTime = 0; // Use this to implement a non-blocking delay function that forces update even if temp hasn't changed
      
      DHT dht;
      float lastTemp;
      float lastHum;
      
      boolean metric = true;
      
      bool lastTripped = 0;   // Used to store last motion sensor value
      boolean FirstBoot = true;
      
      // the below allow you decide if the default state of certain sensors is stored in EEPROM or Controller or always start in a certain state
      // 1 = EEPROM 2 = Controller (e.g. Domoticz), 3 or any other number then they start as with default values
      // If option 1 or 3 is selected then we will also send a message to the controller to tell it the states
      
      // unsigned long WaitBetweenSendingMessages = 150; //how long to wait between sending messages and presenting nodes
      int StoreTempOffset = 2;
      int StoreMotionOnOff = 2;
      int StoreRelayState = 2;
      
      // below are the default states that you can set to be loaded at boot each time
      // these will be reverted to in EEPROM values are corrupted
      bool MotionON = 0;      //enable/disable the PIR reports (1=enabled 0=disabled)
      bool RelayState = 0;    // default state for relays (1 = on, 0 = off)
      
      int TempOffset = 50; // a value of 50 means that initial offset is zero when first loaded.  Tempoffset can be between 0-100
      volatile float ActualTempOffset = (TempOffset / 10.0) - 5.0;  //Adjust temp offset to a decimal between +/- 5 degrees
      
      MyMessage msgHum(CHILD_ID_HUM, V_HUM);
      MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
      MyMessage msgMot(CHILD_ID_MOT, V_TRIPPED);
      MyMessage msgTempOffset(CHILD_ID_TEMP_OFFSET, V_PERCENTAGE);
      MyMessage msgMotOnOff(CHILD_ID_MotionOnOff, V_STATUS);
      MyMessage msgRelay1(1, V_STATUS);
      MyMessage msgRelay2(2, V_STATUS);
      MyMessage msgGestureUpDown(CHILD_ID_GESTUREUD, V_STATUS);
      MyMessage msgGestureLeftRight(CHILD_ID_GESTURELR, V_STATUS);
      MyMessage msgGestureNearFar(CHILD_ID_GESTURENF, V_STATUS);
      
      void before()
      {
      
        // Then set relay pins in output mode
        pinMode(RELAY_1_PIN , OUTPUT);
        pinMode(RELAY_2_PIN , OUTPUT);
        
      
        
        pinMode(DIGITAL_INPUT_SENSOR, INPUT);      // sets the motion sensor digital pin as input
      
      
      
      
      }
      
      void setup()
      {
        // Set gesture sensor interrupt pin as input
        pinMode(APDS9960_INT, INPUT);
          
          //define sensitivity of gesture sensor
          apds.setGestureGain( GestureSensitivity );
        
        dht.setup(HUMIDITY_SENSOR_DIGITAL_PIN);
        // metric = getConfig().isMetric;
      
        // Initialize interrupt service routine for gestures
        
       attachInterrupt(digitalPinToInterrupt(APDS9960_INT), interruptRoutine, FALLING);
      
      
        // Initialize APDS-9960 (configure I2C and initial values)
        if ( apds.init() ) {
          Serial.println(F("APDS-9960 initialization complete"));
        } else {
          Serial.println(F("Something went wrong during APDS-9960 init!"));
        }
        
        // Start running the APDS-9960 gesture sensor engine
        if ( apds.enableGestureSensor(true) ) {
          Serial.println(F("Gesture sensor is now running"));
        } else {
          Serial.println(F("Something went wrong during gesture sensor init!"));
        }
      
      }
      
      void presentation()
      {
        // Send the sketch version information to the gateway and Controller
        sendSketchInfo("MyMultiSensor", "1.4");
      
      
        // Register all sensors to gw (they will be created as child devices)
        present(CHILD_ID_RELAY1, S_BINARY, "Relay 1");
        wait(100);
        present(CHILD_ID_RELAY2, S_BINARY, "Relay 2");
        wait(100);
        present(CHILD_ID_HUM, S_HUM, "Humidity");
        wait(100);
        present(CHILD_ID_TEMP, S_TEMP, "Temperature");
        wait(100);
        present(CHILD_ID_MOT, S_MOTION, "PIR");
        wait(100);
        present(CHILD_ID_TEMP_OFFSET, S_DIMMER, "Temp Calibration");
        wait(100);
        present(CHILD_ID_MotionOnOff, S_BINARY, "PIR Enable/Disable");
        wait(100);
        present(CHILD_ID_GESTUREUD, S_BINARY, "Gesture Up/Down");
        wait(100);
        present(CHILD_ID_GESTURELR, S_BINARY, "Gesture Left/Right");
        wait(100);
        present(CHILD_ID_GESTURENF, S_BINARY, "Gesture Near/Far");
        wait(100);  
       
      }
      
      void firstboot()
      {
        
        }
        
        
      void loop()
      {
        if(FirstBoot)
        {
        Serial.println("FirstBoot sequence started");
        // Set relay to correct state (using eeprom/default/domoticz value)
        switch (StoreRelayState) {
          case 1:
            if (loadState(CHILD_ID_RELAY1) == 1)  {
              digitalWrite(RELAY_1_PIN , RELAY_ON);  
            }
            else
            {
              digitalWrite(RELAY_1_PIN , RELAY_OFF);  
            }
            if (loadState(CHILD_ID_RELAY2) == 1)  {
              digitalWrite(RELAY_2_PIN , RELAY_ON);  
            }
            else
            {
              digitalWrite(RELAY_2_PIN , RELAY_OFF);  
            }
             
              Serial.print("Relay 1 loadstate from EEPROM: ");
              Serial.println(loadState(CHILD_ID_RELAY1));
              Serial.print("Relay 2 loadstate from EEPROM: ");
              Serial.println(loadState(CHILD_ID_RELAY2));
              //best let domoticz know
              send(msgRelay1.set(RelayState));
              wait(100);
              send(msgRelay2.set(RelayState));
              wait(100);
              
              Serial.print("Default Relay state sent to Domoticz: ");
              Serial.println(RelayState);
          break;
            
          case 2: 
              //get Relay Statuses from Domoticz
                Serial.println("Relay status requested from Domoticz");          
                request(CHILD_ID_RELAY1, V_STATUS);
                wait(1000);
                request(CHILD_ID_RELAY2, V_STATUS);
                wait(1000);
                
          break;
          default:
              digitalWrite(RELAY_1_PIN ,  RelayState ? RELAY_ON : RELAY_OFF);
              digitalWrite(RELAY_2_PIN ,  RelayState ? RELAY_ON : RELAY_OFF);
              Serial.print("Relays set to default boot state: ");
              Serial.println(RelayState);
              //
              send(msgRelay1.set(RelayState));
              wait(100);
              send(msgRelay2.set(RelayState));
              wait(100);
              Serial.print("Default Relay state sent to Domoticz: ");
              Serial.println(RelayState);
          break;
          }
        
        // Set tempoffset to correct state (using eeprom/default/domoticz value) - needs to be 0 - 100 otherwise set to no offset
      
          switch (StoreTempOffset)  {
            case 1:
              if (loadState(CHILD_ID_TEMP_OFFSET) >100) {
                ActualTempOffset = 5.0;
              }
              else
              {
                TempOffset = loadState(CHILD_ID_TEMP_OFFSET);
                ActualTempOffset = (TempOffset / 10.0) - 5.0;
              }
                Serial.print("Temp Offset retrieved from eeprom: ");
                Serial.println(ActualTempOffset);
                //let Domoticz know the value
                send(msgTempOffset.set(TempOffset, 1));
                wait(100);
                Serial.print("tempOffset from sensor sent to Domoticz: ");
                Serial.println(TempOffset);
            break;
            case 2:
              //get TempOffSet from Domoticz 
                Serial.println("TempOffset value requested from Domoticz");         
                request(CHILD_ID_TEMP_OFFSET, V_PERCENTAGE);
                wait(1000);
                
            break;
            default:
                Serial.print("Default boot temperature offset is: ");
                Serial.println(ActualTempOffset);
                //let Domoticz know the value
                send(msgTempOffset.set(TempOffset, 1));
                wait(100);
                Serial.print("tempOffset from sensor sent to Domoticz: ");
                Serial.println(TempOffset);    
            break;
          }
      
          // Set PIR enable/disable (using eeprom/default/domoticz value)  
          switch(StoreMotionOnOff) {
            case 1:
              if (loadState(CHILD_ID_MotionOnOff) == 1 || loadState(CHILD_ID_MotionOnOff) == 0) { //check for odd values in EEPROM
                MotionON = loadState(CHILD_ID_MotionOnOff);  
              }
              else {
                Serial.print("Error in PIR Enable/Disable Value in EEPROM");
                Serial.println("Default value used instead");
              } 
              //Let Domoticz know
                send(msgMotOnOff.set(MotionON, 1));
                wait(100);
                Serial.print("PIR ENABLE status from sensor sent to Domoticz: ");
                Serial.println(MotionON);  
            break;
             
            case 2:
              //get PIR enable status from Domoticz
                Serial.println("MotionOnOff status requested from Domoticz");          
                request(CHILD_ID_MotionOnOff, V_STATUS);
                wait(1000);
      
      
            break;
                
      
            default:
                send(msgMotOnOff.set(MotionON, 1));
                wait(100);
                Serial.print("Default PIR ENABLE status used and sent to Domoticz: ");
                Serial.println(MotionON); 
            break;
          }
        wait(2000);
        Serial.println("First boot checks completed");
        FirstBoot = false;
        }
      
        //check if gesture sensor interrupt is triggered
          if( isr_flag == 1 ) {
          detachInterrupt(digitalPinToInterrupt(APDS9960_INT));
          handleGesture();
          isr_flag = 0;
          attachInterrupt(digitalPinToInterrupt(APDS9960_INT), interruptRoutine, FALLING);
      
        }
        
        // Read digital motion value
        if (MotionON) {
          bool tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH;
          if (lastTripped != tripped) {
            Serial.print("New Motion State: ");
            Serial.println(tripped);
            // Send tripped value to gw
            send(msgMot.set(tripped ? "1" : "0"));
            lastTripped = tripped;
          }
        }
      
      
      
        boolean needRefresh = (millis() - lastRefreshTime) > SLEEP_TIME;
        if (needRefresh)
        {
          Serial.println("I'm alive");
          lastRefreshTime = millis();
      
          float temperature = dht.getTemperature() + ActualTempOffset;
          if (isnan(temperature)) {
            Serial.println("Failed reading temperature from DHT");
          }
          else if (temperature != lastTemp  ) {
            lastTemp = temperature;
            if (!metric) {
              temperature = dht.toFahrenheit(temperature);
            }
            send(msgTemp.set(temperature, 1));
            Serial.print("T: ");
            Serial.println(temperature);
          }
          else if (millis() - lastForceUpdateTime > ForceUpdate) {
            lastTemp = temperature;
            lastForceUpdateTime = millis();
            if (!metric) {
              temperature = dht.toFahrenheit(temperature);
            }
            send(msgTemp.set(temperature, 1));
            Serial.print("T: ");
            Serial.println(temperature);
          }
      
      
          float humidity = dht.getHumidity();
          if (isnan(humidity)) {
            Serial.println("Failed reading humidity from DHT");
          }
          else if (humidity != lastHum) {
            lastHum = humidity;
            send(msgHum.set(humidity, 1));
            Serial.print("H: ");
            Serial.println(humidity);
          }
          else if (millis() - lastForceUpdateTime > ForceUpdate) {
            lastHum = humidity;
            lastForceUpdateTime = millis();
            send(msgHum.set(humidity, 1));
            Serial.print("H: ");
            Serial.println(humidity);
          }
        }
      
      }
      
      void interruptRoutine() {
        //Serial.println("Interrupt Routine started");
        isr_flag = 1;
      }
      
      void handleGesture() {
      
       
        
          if ( apds.isGestureAvailable() ) {
      
      
          switch ( apds.readGesture() ) {
            case DIR_UP:
              Serial.println("UP");
              send(msgGestureUpDown.set(GestureUp));
              break;
            case DIR_DOWN:
              Serial.println("DOWN");
              send(msgGestureUpDown.set(GestureDown));
              break;
            case DIR_LEFT:
              Serial.println("LEFT");
              send(msgGestureLeftRight.set(GestureLeft));
              break;
            case DIR_RIGHT:
              Serial.println("RIGHT");
              send(msgGestureLeftRight.set(GestureRight));
              break;
            case DIR_NEAR:
              Serial.println("NEAR");
              send(msgGestureNearFar.set(GestureNear));
              break;
            case DIR_FAR:
              Serial.println("FAR");
              send(msgGestureNearFar.set(GestureFar));
              break;
            default:
              Serial.println("NONE");
          }
        
         }
        
      }
      
      void receive(const MyMessage &message)
      {
       //For debugging just checking why controller sent a msg e.g. was it in response to a request by node  
        switch (message.getCommand()) {                                 // message.getCommand will give us the command type of the incomming message
            case C_SET: 
              Serial.println("msg sent by controller");
            break;
            case C_REQ:
              Serial.println("msg state sent by controller in response to request");
            break;
            default:
              Serial.println("msg isn't C_SET or C_REQ so what you gonna do?");
            break;
         }
        // We only expect V_STATUS (for relays) or V_Percentage (for temp offset) message from controller. But we better check anyway.
        if (message.type == V_STATUS) {
          // Change relay state
      
          if (message.sensor == 1 ) {
            
            digitalWrite(RELAY_1_PIN , message.getBool() ? RELAY_ON : RELAY_OFF);
            // Store state in eeprom
            saveState(message.sensor, message.getBool());
            // Write some debug info
            Serial.print("Incoming Relay 1 State: ");
            Serial.println(message.getBool());
          }
          else if (message.sensor == 2) {
           
            digitalWrite(RELAY_2_PIN , message.getBool() ? RELAY_ON : RELAY_OFF);
            // Store state in eeprom
            saveState(message.sensor, message.getBool());
            // Write some debug info
            Serial.print("Incoming Relay 2 State: ");
            Serial.println(message.getBool());
          }
          else if (message.sensor == CHILD_ID_MotionOnOff) {
      
              if (message.getBool() == 1) {
                MotionON = 1;
                saveState(CHILD_ID_MotionOnOff, MotionON);
              }
              else
              {
                MotionON = 0;
              }
          Serial.print("Motion Sensor on/off state: ");
          Serial.println(MotionON);
          saveState(CHILD_ID_MotionOnOff, MotionON);
          
          }
        }
        else if (message.type == V_PERCENTAGE)  {
          int TempOffset = atoi(message.data);
          ActualTempOffset = (TempOffset / 10.0) - 5.0;
          Serial.print("Temp Offset value: ");
          Serial.println(ActualTempOffset);
          saveState(CHILD_ID_TEMP_OFFSET, TempOffset);
      
        }
        
      
      }
      
      
      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: Compilation Error for Arduino Pro or Pro Mini

      Hi Daniel

      See @mfalkvidd 's post above - have you installed the custom DallasTemparature.h library as well? I had the same problem before and the reason was that I hadn't used this library...

      posted in Troubleshooting
      Ben Andrewes
      Ben Andrewes
    • RE: Compilation Error for Arduino Pro or Pro Mini

      Have you installed the onewire library?

      posted in Troubleshooting
      Ben Andrewes
      Ben Andrewes
    • RE: Controller Calibration of sensors

      Thanks @mfalkvidd - you're right, the interrupt would never be cleared until the code read the gesture. I uncommented the readGesture only to find that the code hanged at that point (think that was why I commented it out before - I'd had a beer or two).

      I think I really need to spend a bit of time learning about the Arduino programming language, and libraries etc as my programming knowledge is based on BASIC 30yrs ago and a bit of VBA at work. At the moment my arduino programming is just hacking stuff together and seeing if it works...

      Anyway I found that it was the library that IDE installed was wrong and I needed to get the library direct from Sparkfun... Now it works fine so I just need to MySensorise it...

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: Controller Calibration of sensors

      @mfalkvidd That looks very cool, great work.

      Unfortunately, I'm having trouble with the code for the apds9960 and I think that the interrupt isn't working properly - it seems to fire once then the interrupt is stuck low. I've now tried a test sketch from Sparkfun (official example sketch) without any mysensors stuff and added some serial prints to read the state of the interrupt pin every 5 secs and it always returns 0. Any idea why this might be? Do I need to send a message to the sensor to reset the interrupt back to high after it runs the interruptRoutine?

      #include <Wire.h>
      #include <SparkFun_APDS9960.h>
      
      // Pins
      #define APDS9960_INT    3  // Needs to be an interrupt pin
      
      // Constants
      
      // Global Variables
      SparkFun_APDS9960 apds = SparkFun_APDS9960();
      volatile int isr_flag = 0;
      
      unsigned long SLEEP_TIME = 5000; // Sleep time between reads (in milliseconds)
      unsigned long lastRefreshTime = 0; // Use this to implement a non-blocking delay function
      void interruptRoutine();
      void handleGesture();
      
      void setup() {
      
        // Set interrupt pin as input
        pinMode(APDS9960_INT, INPUT);
          Serial.println("Pin state is:");
          Serial.println(digitalRead(APDS9960_INT));
        // Initialize Serial port
        Serial.begin(9600);
        Serial.println();
        Serial.println(F("--------------------------------"));
        Serial.println(F("SparkFun APDS-9960 - GestureTest"));
        Serial.println(F("--------------------------------"));
      
        //define sensitivty
        apds.setGestureGain( 0 );
      
          // Initialize interrupt service routine
        
        attachInterrupt(digitalPinToInterrupt(APDS9960_INT), interruptRoutine, FALLING);
      
      
        // Initialize APDS-9960 (configure I2C and initial values)
        if ( apds.init() ) {
          Serial.println(F("APDS-9960 initialization complete"));
        } else {
          Serial.println(F("Something went wrong during APDS-9960 init!"));
        }
        
        // Start running the APDS-9960 gesture sensor engine
        if ( apds.enableGestureSensor(true) ) {
          Serial.println(F("Gesture sensor is now running"));
        } else {
          Serial.println(F("Something went wrong during gesture sensor init!"));
        }
      
      }
      
      void loop() {
      
        boolean needRefresh = (millis() - lastRefreshTime) > SLEEP_TIME;
        if (needRefresh)
        {
          lastRefreshTime = millis();
          Serial.println("I'm Alive");
          Serial.println("Pin state is:");
          Serial.println(digitalRead(APDS9960_INT));
      
        }  
        if( isr_flag == 1 ) {
          Serial.println("Interrupt");
          detachInterrupt(digitalPinToInterrupt(APDS9960_INT));
          handleGesture();
          Serial.print("returned from handling gesture");
          isr_flag = 0;
          Serial.println(isr_flag);
          attachInterrupt(digitalPinToInterrupt(APDS9960_INT), interruptRoutine, FALLING);
          Serial.println("attachInterrupt executed");
        }
      }
      
      void interruptRoutine() {
        Serial.println("Interrupt Routine started");
        isr_flag = 1;
      }
      
      void handleGesture() {
        Serial.println("Handling gesture");
          //if ( apds.isGestureAvailable() ) {
            //Serial.println("apds.isGestureAvailable() has returned true");
      /****************
          switch ( apds.readGesture() ) {
            case DIR_UP:
              Serial.println("UP");
              break;
            case DIR_DOWN:
              Serial.println("DOWN");
              break;
            case DIR_LEFT:
              Serial.println("LEFT");
              break;
            case DIR_RIGHT:
              Serial.println("RIGHT");
              break;
            case DIR_NEAR:
              Serial.println("NEAR");
              break;
            case DIR_FAR:
              Serial.println("FAR");
              break;
            default:
              Serial.println("NONE");
          }
          *******************/
        // }
        
      }
      
      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: DHT11 humidity and temperature fluctuations

      If you are having trouble reading the serial prints you could send a msg to controller stating the value as 100 degrees/100% - this would then give peakson the graph to indicate errors instead of trying to get the serial.

      I am not sure (and as I have only been attempting to program arduinos for a month or so, could be very wrong 🙂 ) but I don't think your if/else statement is structured correctly and the else part is only linked to the if(isnan(temparature)). If

      You could try separate if/else for temp and humidity, i.e.

      if(isnan(temparature) {
      ...error msg
      }
      else {
      ...send temp message
      }
      
      If(isnan(humidity) {
      ...error msg
      }
      else {
      ...send humidity msg
      }
      
      

      I'm also not sure if you need this line:
      delay(dht.getMinimumSamplingPeriod());

      As you are only sampling every 60 seconds anyway...

      posted in General Discussion
      Ben Andrewes
      Ben Andrewes
    • RE: Controller Calibration of sensors

      @mfalkvidd Damn - I hadn't noticed that - would've saved some time! Oh well, I learnt a bit about programming whilst I was doing it... 🙂

      @gohan I have a dallas sensor so might try that, and they are cheap. I think I got a bit carried away with he idea that the DHT would do humidity as well - not that I really know why I want to know the humidity...!

      If it is of any interest, I'm thinking of adding gesture recognition and reporting to the sensor using an APDS-9960 - I've seen a sketch that uses the APDS-9960, is this a good bit of kit or should I try to use something else?

      I sort of have an idea of a sensor which has a couple of relays on that I can control from Domoticz, and also reports temp/hum, presence via PIR, and gesture controls to Domoticz which will then handle the logic.....

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: Controller Calibration of sensors

      @mfalkvidd that worked for me (I had tried it but was saving the data to a different part of the eeprom than I thought).

      Cheers

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: Controller Calibration of sensors

      @gohan said in Controller Calibration of sensors:

      sht31

      Unfortunately as I'm intending to make over 10 of the same sensor cost becomes a consideration - I think the sht31 are about £4 more than the DHTs... My wife only allows me so much pocket money 🙂

      (I also bought a load of DHT11s before I really had any idea of what I was doing so need to use them up)

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: Multiple Relays + Motion sketch, fully customizable, optional timer, manual override

      @gohan - yep added wait(100) between each sensor. To be honest I made a number of small changes without re-uploading and testing between so I'm not sure what solved it... Oh well, at least it works now 🙂

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • Controller Calibration of sensors

      This may well have already been talked about but if it has I couldn't find it so thought I'd ask

      I am aiming to create a multisensor to place in all rooms in my house. As I'm very new to the arduino I thought it would be easier to get one working then just clone it. So I made a sensor with relays, motion, and temp/humidity (DHT11).

      The problem was that the DHT11s had varying accuracy/calibration and e.g. if I put two nodes in the same room they would report wildly different temps. Rather than hard coding the calibration I added a dummy dimmer switch sensor then used the recieved value (a value between 0 and 100%) to adjust the value that the DHT11 was reporting.

      This is the code I made (probably very inefficient but it works)

      int TempOffset = 50; // initial offset is zero when first loaded
      
      //Now divides temp offset by 10 & subtracts 5.  
      //then e.g. 10% received from domoticz gives a temp offset of -4 degrees.  
      //Allows dht offset to be +/- 5 degrees
      float ActualTempOffset = (TempOffset/10)-5;
      
      MyMessage msgTempOffset(CHILD_ID_TEMP_OFFSET, V_PERCENTAGE);
      
      void presentation
      {
       ...other sensors here
      present(CHILD_ID_TEMP_OFFSET, S_DIMMER);
      }
      void receive(const MyMessage &message)
      {
      	... relay stuff here
      	}
          else if (message.type==V_PERCENTAGE)  {
          int TempOffset = atoi(message.data);
          ActualTempOffset = (TempOffset/10)-5;
          Serial.print("New Temp Offset: ");
          Serial.println(ActualTempOffset);
      
          }  
          
      	
      }
      
      
      

      One thing that I would like it to do is to save the calibration state in EEPROM and report it Domoticz on boot to save calibrating each time.

      Can anyone help?

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: Multiple Relays + Motion sketch, fully customizable, optional timer, manual override

      @thierryd Thanks for the reply. In case it helps anyone I ended up individually defining and presenting the relays and their parameters within the sketch rather than using the FOR statement and it worked fine.

      posted in Development
      Ben Andrewes
      Ben Andrewes
    • RE: Multiple Relays + Motion sketch, fully customizable, optional timer, manual override

      I'm having trouble getting Domoticz to see any more than 1 relay. I've tried the MySensors example basic relay sketch and no luck. Then I tried this one (which is amazing btw as I want to have a PIR independent of the relays) and the same problem.

      I've tried to present the sensors individually without the FOR statement, and added a delay between presentation in case that was an issue, also I've tried different output pins on the Arduino, and I've tried multiple boards... Nothing has worked

      I am very much an enthusiastic amateur, so any advice on what to try next much appreciated

      Thanks in advance

      posted in Development
      Ben Andrewes
      Ben Andrewes