Report Relay state to GW

  • Good morning everybody I have following Problem:

    My controller (pimatic) opens via Gateway my Relay which activates a magnetic valve to fill my pond. depending on the water level, measured by my distance sensor.
    By rule pimatic closes the relay if the distance is less or equal to 14cm. NOW: one out of ten my communication fails and pimatic changes the state of the switch in the frontend, therefor the controller thinks the relay is off (valve closed) But in the GW debug I see the the message to turn of was NOACK. Meaning the water keeps running and my pond overflows.

    After reading everything I found Pimatic does not resend when NOACK or refuses Statechange when noack. IS IT POSSIBLE to report the state of the relay to the controller periodically like every time a distance Message gets send? Like correcting the "Wrong" state in the controler?

    Here is my node Sketch:

     * 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 <>
     * Copyright (C) 2013-2015 Sensnology AB
     * Full contributor list:
     * Documentation:
     * Support Forum:
     * 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.
     * Version 1.0 - Henrik Ekblad
     * Example sketch for a "light switch" where you can control light or something 
     * else from both HA controller and a local physical button 
     * (connected between digital pin 3 and GND).
     * This node also works as a repeader for other nodes
    // Enable debug prints to serial monitor
    #define MY_DEBUG 
    #define MY_RF24_PA_LEVEL RF24_PA_MAX
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    // Enabled repeater feature for this node
    #include <SPI.h>
    #include <MySensors.h>
    #include <Bounce2.h>
    #include <NewPing.h>
    #define RELAY_PIN  4  // Arduino Digital I/O pin number for relay 
    #define BUTTON_PIN  3  // Arduino Digital I/O pin number for button 
    #define CHILD_ID_RELAY 1   // Id of the sensor child
    #define RELAY_ON 1
    #define RELAY_OFF 0
    #define CHILD_ID_DIST 10
    #define TRIGGER_PIN  6  // Arduino pin tied to trigger pin on the ultrasonic sensor.
    #define ECHO_PIN     5  // Arduino pin tied to echo pin on the ultrasonic sensor.
    #define MAX_DISTANCE 300 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
    NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.
    MyMessage msgDist(CHILD_ID_DIST, V_DISTANCE);
    int lastDist;
    bool metric = true;
    Bounce debouncer = Bounce(); 
    int oldValue=0;
    bool state;
    MyMessage msgRelay(CHILD_ID_RELAY,V_LIGHT);
    long previousMillis = 0;        // will store last time Distance was measured
    long interval = 10000;           // interval at which to measure (milliseconds) 
    void setup()  
      // Setup the button
      // Activate internal pull-up
      // After setting up the button, setup debouncer
      // Make sure relays are off when starting up
      digitalWrite(RELAY_PIN, RELAY_OFF);
      // Then set relay pins in output mode
      pinMode(RELAY_PIN, OUTPUT);   
      // Set relay to last known state (using eeprom storage) 
      state = loadState(CHILD_ID_RELAY);
      digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
      metric = getControllerConfig().isMetric;
    void presentation()  {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("Relay & Button Distance", "1.0");
      // Register all sensors to gw (they will be created as child devices)
      present(CHILD_ID_RELAY, S_LIGHT);
      present(CHILD_ID_DIST, S_DISTANCE);  
    *  Example on how to asynchronously check for new messages from gw
    void loop() 
      // Get the update value
      int value =;
      if (value != oldValue && value==0) {
          send(msgRelay.set(state?false:true), true); // Send new state and request ack back
      oldValue = value;
      // here is where you'd put code that needs to be running all the time.
      // check to see if it's time to blink the LED; that is, if the 
      // difference between the current time and last time you blinked 
      // the LED is bigger than the interval at which you want to 
      // blink the LED.
      unsigned long currentMillis = millis();
      if(currentMillis - previousMillis > interval) {
        // save the last time you blinked the LED 
        previousMillis = currentMillis;   
    int dist = metric?sonar.ping_cm():sonar.ping_in();
      Serial.print("Ping: ");
      Serial.print(dist); // Convert ping time to distance in cm and print result (0 = outside set distance range)
      Serial.println(metric?" cm":" in");
      if (dist != lastDist) {
          lastDist = dist;
     // sleep(SLEEP_TIME);
    void receive(const MyMessage &message) {
      // We only expect one type of message from controller. But we better check anyway.
      if (message.isAck()) {
         Serial.println("This is an ack from gateway");
      if (message.type == V_LIGHT) {
         // Change relay state
         state = message.getBool();
         digitalWrite(RELAY_PIN, state?RELAY_ON:RELAY_OFF);
         // Store state in eeprom
         saveState(CHILD_ID_RELAY, state);
         // Write some debug info
         Serial.print("Incoming change for sensor:");
         Serial.print(", New status: ");

  • It's pretty easy to send back the actual state of the relay.

    But imho there are several options to improve the behaviour of the whole thing:

    • if it's more secure to start the whole thing with the relay switched off instead of reading value from EEPROM. Then ask the controller about the desired state and keep it off until message arrives or button is pressed?
    • keep track of the actual state of your relay within the loop(). By now, the switching logic of the button/switch seems to be weired. Does this work as expected?
    • if it's a security function: let the node decide whether the relay should be switched off, dependend on the meassured value and the state of the relay. Just inform the controller it had been switched off.

    It might be necessary to add some overriding functionality (eg. keep relay on for x minutes if it has been switched on using the button and so on).