How is a message from the controller written to a digital pin?



  • First of im sorry for this probably stupid question. Ive been reading a the API, example sketches, and arduino tutorials for a couple of nights now. With all i learned i was able to write some code, but i'm very stuck at the point where messages from the controller are actually written to a pin of the memory of the arduino.

    To learn how to use Arduino and Mysensors, i want to make a very simple relay actor to start with. I think i have all the pin setup right. The commented debug shows the values right in the serial monitor. The V_LIGHT is seen in Domoticz and it seems like it sends the values.

    Even with all the reading and trying, i still dont understand how i can receive the messages and get them in my code. For my application i dont need to remember the values once the arduino is turned off. Can you guys help me understand? I'm sorry i'm such a noob.

    I'm trying to hook up a irrigation computer to my controller (Domoticz) You can find the whole story here. I think i figured out how i'm going to make Domoticz sent a "on for X minutes" code. I'm either using V_CUSTOM or V_DIMMER. Domoticz will sent a value of 10, 20, 30, 40, that represents 1,5,10, 20, etc, minutes on time. When the time is counted down to 0 i want the system to turn off again and sent a "off" command to the controller.

    // -------- USED LIBARIES -----------
    #include <SPI.h>
    #include <MySensor.h>
    
    
    // -----------DEFINE----------------
    
    // Name and version of sketch. This will appear in conroler
    #define MYS_NAME "Irrigation Computer"
    #define MYS_VER "0.1.1"
    
    // Defines which IO pins are used 
    #define SWITCH1 4
    #define SWITCH2 5
    #define MOTOR1 6
    #define MOTOR2 7
    
    MySensor gw;
    
    
    // ------------SETUP---------------      
    
    // *** Identification ***  
    void setup() {
      gw.begin(); //mysensors initialization 
      gw.sendSketchInfo(MYS_NAME, MYS_VER); //sent sketch info an version to controler
      gw.present(101, S_LIGHT); //child ID and type of device 1 as seen in controler 
      gw.present(102, S_LIGHT); //child ID and type of device 2 as seen in controler
      
    // *** IO SETUP ***
      // Switch 1
      pinMode(SWITCH1,INPUT_PULLUP); //set switch 1 as a input (pin number defined in DEFINE)
      // Switch 2
      pinMode(SWITCH2,INPUT_PULLUP); //set switch 2 as a output (pin number defined in DEFINE)
      // Motor 1
      pinMode(MOTOR1,OUTPUT); //set motor 1 as a output (pin number defined in DEFINE)
      digitalWrite(MOTOR1,LOW); //Activate internal pull-down
      // Motor 2
      pinMode(MOTOR2,OUTPUT); //set motor 2 as a output (pin number defined in DEFINE)
      digitalWrite(MOTOR2,LOW); //Activate internal pull-down  
    }
    
    // ------------LOOP---------------
    
    void loop() 
    {
      gw.process();
       
      /* *** Serial print for debugging ***  
      Serial.println("");
      Serial.println("");
      Serial.println("");
      Serial.println("Current I/O values");
    
      Serial.print("Switch 1= ");
      Serial.println(digitalRead(SWITCH1));
    
      Serial.print("Motor 1= ");
      Serial.println(digitalRead(MOTOR1));
      
      Serial.print("Switch 2= ");
      Serial.println(digitalRead(SWITCH2));
    
      Serial.print("Motor 2= ");
      Serial.println(digitalRead(MOTOR2));
      
      delay(1000);
      /*
    }
    

  • Plugin Developer

    @SuperKris

    Hi!

    You should add an incoming message callback function and add an argument to the begin method referencing the callback.

    Look at the relay sketch example in the build section of the mysensors site. At the bottom of the sketch there is the incoming message callback.



  • I'm not sure is i understand anything of that fist sentence... Im such a noob 😞 Can you please clarify?

    Off course i had a look at the relay actor example. I tried to recreate the basics of it, but i'm not able to write message from the controller to a pin. I think my sketch receives the data from the controller, there was defiantly something in the serial monitor, but i just dont understand how this part works.

    I've read everything i could understand in the API, but for me that doesnt seem te be enough for me to understand how i can use the radio signal transmitted by the controller.

    If i understand right, a sensor that only transmits should just sent a data message to the controller. While i didn't try this yet, i do think i understand the basics from reading the API. The receiving part is not explained as detailed, or am i missing something?

    Please tell me if i understand this right: I have to put gw.process(); in the void loop part so the mysensors library keeps checking for messages. Is this true, or are there other ways? I would assume this uses a lot of battery, and i want to run on just 2 AA batteries.

    The rest of code does not take place in the void loop. Below is the part from the example sketch that i assume makes the relay switch.

    }
    void incomingMessage(const MyMessage &message) {
      // We only expect one type of message from controller. But we better check anyway.
      if (message.type==V_LIGHT) {
         // Change relay state
         digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
         // Store state in eeprom
         gw.saveState(message.sensor, message.getBool());
         // Write some debug info
         Serial.print("Incoming change for sensor:");
         Serial.print(message.sensor);
         Serial.print(", New status: ");
         Serial.println(message.getBool());
       } 
    

    So if i read this right this does the following:
    If the message type is equal too V_LIGHT (How does the arduino know which message i'm talking about?)
    Then change the state of a digital output.... a lot that i do not understand....

    Anyway, if i bring this back to the basics, i would assume the following would work:

    void incomingMessage(const MyMessage &message) {
      if (message.type == V_LIGHT) {
         // Change relay state
         digitalWrite(MOTOR1, HIGH);
      }
    }
    

    But this does absolutely nothing.


  • Plugin Developer

    @SuperKris

    Sorry for the lingo.

    From your reply I think you've understood very well so far.

    If you want to run on batteries you should sleep as much as possible. So then you should add a call to the sleep method, i.e. gw.sleep([TIME IN MILLISECONDS]). Read more about that in the API. But the problem is then, that you can't receive messages from the controller while sleeping. There are possible workarounds, like waking up every now and then to let the node check for messages from the controller. But in the 1.5 releases you have to write all code for that yourself, so I wouldn't recommend it for a beginner. In the dev branch version (2.0), which is under continuous development, there is support for smart sleep, which simplifies the process of sleeping, waking and checking for controller messages before sleeping again. The controller needs to support this though.

    Anyway, if you can, it's best to start with a non battery driven node, if you expect messages from the controller after setup. That way you don't need to sleep, and can call gw.process each lap in the loop, like you said.

    The arduino node knows all possible message types from the mysensors library that is imported in the beginning of the sketch. message.type is the type attribute of the message argument that gets passed into the function. Sorry for the lingo again. Each message that is received will have a message subtype. This is part of the mysensors message protocol. When the message comes in to the node, the incomingMessage function will be called, from the gw.process method, and the message object which holds different attributes of the message is passed into the incomingMessage function as an argument. The argument is the word inside the parenthesis after the function name, simply put, in this case message.

    In the end of the library API page on the site, you will find info about message manipulation. Among other things there are "getters" for getting the different attributes of the message object. For example message.getBool().

    You should add

    message.getBool()?HIGH:LOW
    

    instead of just HIGH to your modified incomingMessage function. The BOOL?HIGH:LOW part is a short form of making an IF statement. That way you can send a 1 as payload to switch the motor pin HIGH and a 0 to switch it to LOW.

    How have you tested this? Have you tried sending a message to the node of subtype V_LIGHT with a payload of either "1" or "0"? If you're using a controller it probably supports this if you present the correct sensor/actuator type. Hook up your node to a computer with USB / serial connection and start the serial monitor in the Arduino IDE. Then you can watch the messages from/to the node.

    Also test just switching the motor pin HIGH/LOW directly in the loop with a wait or sleep of some seconds in between, so you know the pin is acting properly. Of course you need a readout for the pin somehow. You can use a LED and a resistor if you don't want to connect anything larger while testing.

    Edit: Don't forget to add the name of the incoming message function as first argument to the begin method. Read about initializing the library in the API on the site, section "Starting up the library".



  • Thank you very, very much for all that info. I think it helped a lot, but i can still not get it to do anything with te received message.

    I did learn a not of other thing about arduino, and was able to write some of my code needed for the I/O. The only thing i need it to do now is to change boolean S_VALVE1 but i just cant get it to work! I tried reading the api again, but that stuff just looks very advanced to me. How do i change the boolean with by sending a 1 or 0 from my controler? (Domoticz). Af far as i can see, this part is working.

    Can anyone tell me what is wrong in my sketch, and how i can fix it?

    If i can get this to work, ill try to switch to a V_CUSTOM or V_DIMMER that set a countdown which controlls the boolean, but i want to start simple...

    // -------- USED LIBARIES -----------
    #include <SPI.h>
    #include <MySensor.h>
    
    
    // -----------DEFINE----------------
    
    // Name and version of sketch. This will appear in conroler
    #define MYS_NAME "Irrigation Computer"
    #define MYS_VER "0.1.1"
    
    // Defines which IO pins are used 
    #define SWITCH1 4
    #define SWITCH2 5
    #define MOTOR1 6
    #define MOTOR2 7
    
    // Variables for switching the valves 
    boolean S_VALVE1 = false; // desired status valve 1
    boolean S_VALVE2 = false; // desired status valve 2
    int ONTIME1 = 0; // turn on for X time (countdown)
    int ONTIME2 = 0; // turn on for X time (countdown)
    
    //TEST PURPOSE ONLY!!!
    //#define FAKEONMESSAGE1 3 //TEST PURPOSE ONLY!!!
    
    MySensor gw;
    
    // ------------SETUP---------------      
    
    // *** Identification ***  
    void setup() {
      gw.begin(); //mysensors initialization 
      gw.sendSketchInfo(MYS_NAME, MYS_VER); //sent sketch info an version to controler
      gw.present(101, S_LIGHT); //child ID and type of device 1 as seen in controler 
      gw.present(102, S_LIGHT); //child ID and type of device 2 as seen in controler
      
    // *** IO SETUP ***
      // Switch 1
      pinMode(SWITCH1,INPUT_PULLUP); //set switch 1 as a input (pin number defined in DEFINE)
      // Switch 2
      pinMode(SWITCH2,INPUT_PULLUP); //set switch 2 as a output (pin number defined in DEFINE)
      // Motor 1
      pinMode(MOTOR1,OUTPUT); //set motor 1 as a output (pin number defined in DEFINE)
      digitalWrite(MOTOR1,LOW); //Activate internal pull-down
      // Motor 2
      pinMode(MOTOR2,OUTPUT); //set motor 2 as a output (pin number defined in DEFINE)
      digitalWrite(MOTOR2,LOW); //Activate internal pull-down  
    
    //TEST PURPOSE ONLY!!!
    //pinMode(FAKEONMESSAGE1,INPUT_PULLUP); //TEST PURPOSE ONLY!!!
    
    
    }
    
    // ------------LOOP---------------
    
    void loop() 
    {
      gw.process();
       
      // *** Serial print for debugging ***  
      Serial.println("");
      Serial.println("");
      Serial.println("");
      Serial.println("Current I/O values");
    
    //  Serial.print("Fake on message= "); //TEST PURPOSE ONLY!!!
    //  Serial.println(digitalRead(FAKEONMESSAGE1)); //TEST PURPOSE ONLY!!!
    
      Serial.print("status on boolean= "); //TEST PURPOSE ONLY!!!
      Serial.println(S_VALVE1); //TEST PURPOSE ONLY!!!
    
      Serial.print("Switch 1= ");
      Serial.println(digitalRead(SWITCH1));
    
      Serial.print("Motor 1= ");
      Serial.println(digitalRead(MOTOR1));
      
      Serial.print("Switch 2= ");
      Serial.println(digitalRead(SWITCH2));
    
      Serial.print("Motor 2= ");
      Serial.println(digitalRead(MOTOR2));
    
      delay(500); 
      
    
    //  if (digitalRead(FAKEONMESSAGE1) == HIGH) //TEST PURPOSE ONLY!!!
    //    {
    //    S_VALVE1 = true; //TEST PURPOSE ONLY!!!
    //    }
    //  if (digitalRead(FAKEONMESSAGE1) == LOW) //TEST PURPOSE ONLY!!!
    //    {
    //    S_VALVE1 = false; //TEST PURPOSE ONLY!!!
    //    }
    
      // If valve 1 should be on, but switch 1 sais valve 1 is still off, turn on motor 1 to open te valve
      if (S_VALVE1 == true && digitalRead(SWITCH1) == HIGH)
        {
        digitalWrite(MOTOR1, HIGH);  
        }
      // If valve 1 should be on, and switch 1 sais valve 1 is currely on, the valve is in the right position, and the motor should stop turning 
      if (S_VALVE1 == true && digitalRead(SWITCH1) == LOW)
        {
        digitalWrite(MOTOR1, LOW);
        }
      //If valve 1 should be off, but switch 1 sais valve 1 is still on, turn on motor to close the valve
      if (S_VALVE1 == false && digitalRead(SWITCH1) ==  LOW)
        {
      // If valve 1 should be off, and switch 1 sais valve 1 is currently off, the valve is in the right position, and the motor should stop turning 
      if (S_VALVE1 == false && digitalRead(SWITCH1) == HIGH)
        {
        digitalWrite(MOTOR1, LOW);
        }
    }
    }
    
    void incomingMessage(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) 
         {
         S_VALVE1 = message.getBool();
         }   
      }
    
    

  • Plugin Developer

    @SuperKris

    First you should add the name of the incoming message function to the begin method call in your setup function:

    void setup() {
      gw.begin(incomingMessage);
    ...
    }
    

    It seems as you've forgotten one out of four changes of the motor pin in your loop:

      if (S_VALVE1 == true && digitalRead(SWITCH1) == HIGH)
        {
        digitalWrite(MOTOR1, HIGH);  
        }
      // If valve 1 should be on, and switch 1 sais valve 1 is currely on, the valve is in the right position, and the motor should stop turning 
      if (S_VALVE1 == true && digitalRead(SWITCH1) == LOW)
        {
        digitalWrite(MOTOR1, LOW);
        }
      //If valve 1 should be off, but switch 1 sais valve 1 is still on, turn on motor to close the valve
      if (S_VALVE1 == false && digitalRead(SWITCH1) ==  LOW)
        {  // THIS WAS MISSING
        digitalWrite(MOTOR1, HIGH);
        }
      // If valve 1 should be off, and switch 1 sais valve 1 is currently off, the valve is in the right position, and the motor should stop turning 
      if (S_VALVE1 == false && digitalRead(SWITCH1) == HIGH)
        {
        digitalWrite(MOTOR1, LOW);
        }
    

    Depending on how your controller updates its known state of an actuator, you should consider sending back the updated state after the change of state, eg when S_LIGHT/S_VALVE1 changes from true to false and vice versa. You have to first declare a message variable with correct child id and type. This is usually done outside any function, in the global scope. Then you use the send method and a setter on the msg to send in the new value, either in incomingMessage or loop function. Eg:

    MyMessage msg(101, V_LIGHT);
    void setup() {
    ...
    }
    ...
    void incomingMessage(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) 
      {
        S_VALVE1 = message.getBool();
        gw.send(msg.set(S_VALVE1 ? 1 : 0));
      }
    }
    

    Some controllers also demand that you send in an initial value of the sensor or actuator to the controller. Do this at the end of the setup function:

    void setup() {
    ...
      gw.send(msg.set(S_VALVE1 ? 1 : 0));
    }
    

    Currently you're not sending any messages which are flagged with acknowledgement set to true, so you can remove the if statement about message.isAck in incomingMessage.



  • Thanks! This helps me understand a little bit better. I tried adding the incoming.Message part before, but i keep ketting this error when i try to upload:

    'incomingMessage' was not declared in this scope

    I do not understand why it does this! I cant find any faults in the syntax, and other sketches that use this do not give this error. (like the relay actor example)

    This is the updated code now:

    // -------- USED LIBARIES -----------
    #include <SPI.h>
    #include <MySensor.h>
    
    
    // -----------DEFINE----------------
    
    // Name and version of sketch. This will appear in conroler
    #define MYS_NAME "Irrigation Computer"
    #define MYS_VER "0.1.1"
    
    // Defines which IO pins are used 
    #define SWITCH1 4
    #define SWITCH2 5
    #define MOTOR1 6
    #define MOTOR2 7
    
    // Variables for switching the valves 
    boolean S_VALVE1 = false; // desired status valve 1
    boolean S_VALVE2 = false; // desired status valve 2
    int ONTIME1 = 0; // turn on for X time (countdown)
    int ONTIME2 = 0; // turn on for X time (countdown)
    
    MySensor gw;
    MyMessage msg(101, V_LIGHT);
    
    //TEST PURPOSE ONLY!!!
    //#define FAKEONMESSAGE1 3 //TEST PURPOSE ONLY!!!
    
    
    // ------------SETUP---------------      
    
    // *** Identification ***  
    void setup() {
      gw.begin(incomingMessage); //mysensors initialization 
      gw.sendSketchInfo(MYS_NAME, MYS_VER); //sent sketch info an version to controler
      gw.present(101, S_LIGHT); //child ID and type of device 1 as seen in controler 
      gw.present(102, S_LIGHT); //child ID and type of device 2 as seen in controler
      
    // *** IO SETUP ***
      // Switch 1
      pinMode(SWITCH1,INPUT_PULLUP); //set switch 1 as a input (pin number defined in DEFINE)
      // Switch 2
      pinMode(SWITCH2,INPUT_PULLUP); //set switch 2 as a output (pin number defined in DEFINE)
      // Motor 1
      pinMode(MOTOR1,OUTPUT); //set motor 1 as a output (pin number defined in DEFINE)
      digitalWrite(MOTOR1,LOW); //Activate internal pull-down
      // Motor 2
      pinMode(MOTOR2,OUTPUT); //set motor 2 as a output (pin number defined in DEFINE)
      digitalWrite(MOTOR2,LOW); //Activate internal pull-down  
    
      gw.send(msg.set(S_VALVE1 ? 1 : 0));
    
    //TEST PURPOSE ONLY!!!
    //pinMode(FAKEONMESSAGE1,INPUT_PULLUP); //TEST PURPOSE ONLY!!!
    
    }
    
    // ------------LOOP---------------
    
    void loop() 
    {
      gw.process();
       
      // *** Serial print for debugging ***  
      Serial.println("");
      Serial.println("");
      Serial.println("");
      Serial.println("Current I/O values");
    
    //  Serial.print("Fake on message= "); //TEST PURPOSE ONLY!!!
    //  Serial.println(digitalRead(FAKEONMESSAGE1)); //TEST PURPOSE ONLY!!!
    
      Serial.print("status on boolean= "); //TEST PURPOSE ONLY!!!
      Serial.println(S_VALVE1); //TEST PURPOSE ONLY!!!
    
      Serial.print("Switch 1= ");
      Serial.println(digitalRead(SWITCH1));
    
      Serial.print("Motor 1= ");
      Serial.println(digitalRead(MOTOR1));
      
      Serial.print("Switch 2= ");
      Serial.println(digitalRead(SWITCH2));
    
      Serial.print("Motor 2= ");
      Serial.println(digitalRead(MOTOR2));
    
      delay(500); 
      
    
    //  if (digitalRead(FAKEONMESSAGE1) == HIGH) //TEST PURPOSE ONLY!!!
    //    {
    //    S_VALVE1 = true; //TEST PURPOSE ONLY!!!
    //    }
    //  if (digitalRead(FAKEONMESSAGE1) == LOW) //TEST PURPOSE ONLY!!!
    //    {
    //    S_VALVE1 = false; //TEST PURPOSE ONLY!!!
    //    }
    
      // If valve 1 should be on, but switch 1 sais valve 1 is still off, turn on motor 1 to open te valve
      if (S_VALVE1 == true && digitalRead(SWITCH1) == HIGH)
        {
        digitalWrite(MOTOR1, HIGH);  
        }
      // If valve 1 should be on, and switch 1 sais valve 1 is currely on, the valve is in the right position, and the motor should stop turning 
      if (S_VALVE1 == true && digitalRead(SWITCH1) == LOW)
        {
        digitalWrite(MOTOR1, LOW);
        }
      //If valve 1 should be off, but switch 1 sais valve 1 is still on, turn on motor to close the valve
      if (S_VALVE1 == false && digitalRead(SWITCH1) ==  LOW)
        {
        digitalWrite(MOTOR1, HIGH); 
        }  
      // If valve 1 should be off, and switch 1 sais valve 1 is currently off, the valve is in the right position, and the motor should stop turning 
      if (S_VALVE1 == false && digitalRead(SWITCH1) == HIGH)
        {
        digitalWrite(MOTOR1, LOW);
        }
    }
    }
    
    void incomingMessage(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) 
      {
        S_VALVE1 = message.getBool();
        gw.send(msg.set(S_VALVE1 ? 1 : 0));
      }
    }
    

    Thanks for the tip on the missing I/O code. I think i accidentally deleted it trying all kinds of stuff to make the communication work.


  • Plugin Developer

    I think you have an extra closing curly bracket just before the start of the incomingMessage function. Try removing that last curly bracket, and compile again. Check your indentation also. If you're consistent with the indentation, it's easier to spot things like that.



  • @martinhjelmare said:

    It works, thank you very, very, much!!! I checked the brackets multiple times, but i did not see the fault! But it works now!

    I cleaned up the code a bit, and tried to copy and modify it for the 2nd valve. The code below does not work. I understand why it doesnt work, but i do not understand how to fix it.

    The incommingMessage function does not seem to check for what variable/child ID the message was meant. It only checks if the message is of the V_LIGHT type. If the message is V_LIGHT, it changes the boolean S_VALVE1. It however also changes S_VALVE2.

    I does not check for the child ID that is sent by the controller. How do i make it check for the child ID so i can switch them individually?

    // -------- USED LIBARIES -----------
    #include <MySensor.h>
    #include <SPI.h>
    
    // -----------DEFINE----------------
    
    // Names and identification. This will appear in controller
    #define MYS_NAME "Irrigation Computer"
    #define MYS_VER "0.2"
    #define NODE_ID 100 //Used for the node ID
    #define CHILD_ID1 101 //Used for valve 1
    #define CHILD_ID2 102 //Used for valve 2
    
    // Defines which IO pins are used 
    #define SWITCH1 4
    #define SWITCH2 5
    #define MOTOR1 6
    #define MOTOR2 7
    
    // Variables for switching the valves 
    boolean S_VALVE1 = false; // desired status valve 1
    boolean S_VALVE2 = false; // desired status valve 2
    int ONTIME1 = 0; // turn on for X time (countdown)
    int ONTIME2 = 0; // turn on for X time (countdown)
    
    MySensor gw;
    MyMessage MSG_V1(CHILD_ID1, V_LIGHT);
    MyMessage MSG_V2(CHILD_ID2, V_LIGHT);
    
    // ------------SETUP---------------      
    // *** Identification ***  
    void setup(){
      gw.begin(incomingMessage, NODE_ID, false); //mysensors initialization. Function incomming message
      gw.sendSketchInfo(MYS_NAME, MYS_VER); //sent sketch info an version to controler
      gw.present(CHILD_ID1, S_LIGHT); //child ID and type of device 1 as seen in controler 
      gw.present(CHILD_ID2, S_LIGHT); //child ID and type of device 2 as seen in controler
      
      // *** IO SETUP ***
      pinMode(SWITCH1,INPUT_PULLUP); //set switch 1 as a input (pin number defined in DEFINE)
      pinMode(SWITCH2,INPUT_PULLUP); //set switch 2 as a output (pin number defined in DEFINE)
      pinMode(MOTOR1,OUTPUT); //set motor 1 as a output (pin number defined in DEFINE)
      digitalWrite(MOTOR1,LOW); //Activate internal pull-down for motor 1
      pinMode(MOTOR2,OUTPUT); //set motor 2 as a output (pin number defined in DEFINE)
      digitalWrite(MOTOR2,LOW); //Activate internal pull-down for motor 2
    
    // *** MySensors functions *** 
      gw.send(MSG_V1.set(S_VALVE1 ? 1 : 0)); // Sents status of valve back to controler
      gw.send(MSG_V2.set(S_VALVE2 ? 1 : 0)); // Sents status of valve back to controler
    
    }
    // ------------LOOP---------------
    void loop() 
    {
      gw.process();
       
    /*// *** Serial print for debugging ***  
      Serial.println("");
      Serial.println("");
      Serial.println("");
      Serial.println("------------------------------");
      Serial.println("Current I/O values");
      Serial.println("------------------------------");
      Serial.print("Desired status of valve 1= ");
      Serial.println(S_VALVE1);
      Serial.print("Switch 1= ");
      Serial.println(digitalRead(SWITCH1));
      Serial.print("Motor 1= ");
      Serial.println(digitalRead(MOTOR1));
      Serial.println("");
      Serial.print("Desired status of valve 2= ");
      Serial.println(S_VALVE2); //TEST PURPOSE ONLY!!
      Serial.print("Switch 2= ");
      Serial.println(digitalRead(SWITCH2));
      Serial.print("Motor 2= ");
      Serial.println(digitalRead(MOTOR2));
      Serial.println("------------------------------");
      delay(500); */
    
    // ------------ I/O logic of valve 1 -------------------
    // This code controles the valves based on the status of boolean S_VALVE1. 0 = valve should be closes, 1 = valve should be open
      // If valve 1 should be on, but switch 1 sais valve 1 is still off, turn on motor 1 to open te valve
      if (S_VALVE1 == true && digitalRead(SWITCH1) == HIGH)
        {
        digitalWrite(MOTOR1, HIGH);  
        }
      // If valve 1 should be on, and switch 1 sais valve 1 is currely on, the valve is in the right position, and the motor should stop turning 
      if (S_VALVE1 == true && digitalRead(SWITCH1) == LOW)
        {
        digitalWrite(MOTOR1, LOW);
        }
      //If valve 1 should be off, but switch 1 sais valve 1 is still on, turn on motor to close the valve
      if (S_VALVE1 == false && digitalRead(SWITCH1) == LOW)
        {
        digitalWrite(MOTOR1, HIGH); 
        }  
      // If valve 1 should be off, and switch 1 sais valve 1 is currently off, the valve is in the right position, and the motor should stop turning 
      if (S_VALVE1 == false && digitalRead(SWITCH1) == HIGH)
        {
        digitalWrite(MOTOR1, LOW);
        } 
    // -----------End of I/O logic of valve 1------------------
    // Below is the logic of valve 2. The code works the same a valve 1, but is uncommented and more compact.
      if (S_VALVE2 == true && digitalRead(SWITCH2) == HIGH)
        {digitalWrite(MOTOR2, HIGH);} 
      if (S_VALVE2 == true && digitalRead(SWITCH2) == LOW)
        {digitalWrite(MOTOR2, LOW);}
      if (S_VALVE2 == false && digitalRead(SWITCH2) == LOW)
        {digitalWrite(MOTOR2, HIGH);}  
      if (S_VALVE2 == false && digitalRead(SWITCH2) == HIGH)
        {digitalWrite(MOTOR2, LOW);} 
    // -----------End of I/O logic of valve 2------------------ 
    }
    
    void incomingMessage(const MyMessage &message) {
      if (message.type == V_LIGHT) 
        {
        S_VALVE1 = message.getBool();
        gw.send(MSG_V1.set(S_VALVE1 ? 1 : 0));
        }
      if (message.type == V_LIGHT) 
        {
        S_VALVE2 = message.getBool();
        gw.send(MSG_V2.set(S_VALVE2 ? 1 : 0));
        }
    }
    

  • Plugin Developer

    You have message.sensor that you can use in the incomingMessage function to only apply logic to a specific child id. message.sensor is the child id of the sensor that the message is meant for. See the relay sketch example in the build section on the site, for an example how to use this attribute.



  • @martinhjelmare said:

    Thanks again! It works now! I thought there would be a function similar to message.type, but i could not find it. The relay sketch is still a bit confusing to me, but i came up with the following solution. It seems to work...

    Is this a effective way to do this, or is there a much easier way without using the if statement?

    void incomingMessage(const MyMessage &message) {
      if (message.type == V_LIGHT && message.sensor == CHILD_ID1)
        {
        S_VALVE1 = message.getBool();
        gw.send(MSG_V1.set(S_VALVE1 ? 1 : 0));
        }
      if (message.type == V_LIGHT && message.sensor == CHILD_ID2)
        {
        S_VALVE2 = message.getBool();
        gw.send(MSG_V2.set(S_VALVE2 ? 1 : 0));
        }
    }
    

  • Plugin Developer

    Well you could store the boolean variables for the valves in an array, and use the sensor child id as the index of the variables in the array. You can also use the setSensor setter on the message variable (MSG_V1) to change which sensor child id the message belongs to. That way, you only need to declare one message variable. You can use two setters on the same line like this:

    // Set child id 1 to 0 to simplify using it as index in an array
    #define CHILD_ID1 0
    // Set child id 2 to 1 which is the next index after index 0.
    #define CHILD_ID2 1
    // Declare an array of type boolean of size 2.
    boolean VALVES[2];
    // Declare the message with CHILD_ID1.
    MyMessage MSG(CHILD_ID1, V_LIGHT);
    void setup() {
    ...
    }
    ...
    void incomingMessage(const MyMessage &message) {
      if (message.type == V_LIGHT) {
        // Set array element at index message.sensor to boolean value from message payload.
        VALVES[message.sensor] = message.getBool();
        // Set child id to child id of message.sensor and payload to either 1 or 0 for message, and send message.
        gw.send(MSG.setSensor(message.sensor).set(message.getBool() ? 1 : 0));
      }
    }
    

    Sorry... there was a lot of edits. Now I'm done.... 😄


Log in to reply
 

Suggested Topics

  • 1
  • 1
  • 3
  • 2
  • 10
  • 6

15
Online

11.4k
Users

11.1k
Topics

112.7k
Posts