LCD Clock and Text sensor node with new V_TEXT

  • Hero Member

    With good cooperation of @hek and @GizMoCuz (Domoticz) a TEXT sensor is introduced. It is currently in development stage but I hope will make it to production soon. The V_TEXT variable makes simple text message transfer possible intra-node and between node and controller.

    Below a first experiment. More to follow!

    "Sensor Node" My sensorboard (can be any board or just a nano with wires):

    "LCD Display" (standard 2x16 char, I2C):

    start the sketch (end of post). Activated sensor in Domoticz:

    You can update the text in Domoticz with JSON (or many other ways). The last part is the text %01 MySensors

    and on the LCD

    I'm happy....

    If you like to experiment: get the development version of MySensors or just add the V_TEXT as described in the example sketch:

     PROJECT: MySensors / LCD display for text from controller
     DATE: september 8, 2015/ last update: september 8, 2015
     FILE: AWI_LCD_49.ino
     LICENSE: Public domain
     Hardware: tbd ..MYS Ceech - ATmega328p board w/ NRF24l01
    	and MySensors 1.5 ()
    	MySensors - Development (as of sept 2015)
    	display time & 2 lines of text from Controller Text sensors
    #include <MySensor.h>          				// Mysensor network
    #include <SPI.h>
    #include <LiquidCrystal_I2C.h>
    #include <Time.h>   						//
    #include <Wire.h>		         			
    // uncomment if you are using the DEVELOPMENT version with V_TEXT & V_INFO defined (better to use development MyMessage.h)
    //const byte V_TEXT = 47 ;					// values taken from development edition MyMessage.h
    //const byte S_INFO = 36 ;
    const byte nodeId = 49 ;					// MySensors fixed node id
    const byte LCD1_CHILD = 8 ;					// LCD line 1
    const byte LCD2_CHILD = 9 ;					// LCD line 2
    char lastLCD1[21] = "Line1 - first   ";		// define & init before first receive
    char lastLCD2[21] = "Line2 - second  ";
    boolean timeReceived = false ;
    // timers for loop delays
    unsigned long lastUpdate=0, lastRequest=0, lastDisplay=0;
    int display_no = 0 ; 						// current display
    // *** Definition and initialisation
    // define the MySensor network
    MyTransportNRF24 transport(9,10); 			// Sensoduino (8,7) Ceech board, 3.3v (7,8)  (pin default 9,10)
    MySensor gw(transport);  
    // Initialize messages for sensor network
    MyMessage textMsg(0, V_TEXT);
    //                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
    LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
    // OPTIONAL: Custom characters for display - Units)
    byte heart[8] = { B00000, B01010, B11111, B11111, B01110, B00100, B00000, B00000};
    void setup(void){
        //Serial in Sensor network = 115200
        gw.begin(incomingMessage, nodeId); 					// this node is 49 fixed 
        //Send the sensor node sketch version information to the gateway
        gw.sendSketchInfo("AWI_LCD text 49", "1.1");
     	gw.present(LCD1_CHILD, S_INFO, "LCD line1");		// new S_type 20150905 (not know by domoticz)
        gw.present(LCD2_CHILD, S_INFO, "LCD_line2");
    	gw.send(textMsg.setSensor(LCD1_CHILD).set("-"));	// initialize the V_TEXT at controller for sensor to none (trick for Domoticz)
    	// Initializations
        gw.requestTime(receiveTime);						// get the time from controller (handled by receiveTime)
        // ** LCD display **
    	Wire.begin();										// I2C
        lcd.begin(16, 2);							    	// LCD 2 lines * 16 char.
        lcd.setCursor(0, 0);
    	lcd.createChar(1, heart);
        // lcd.write(byte(0)); // write units
    void loop(void){
        // timer for loop delays
        unsigned long now = millis();
        gw.process() ;
        // If no time has been received yet, request it every 10 second from controller
        // When time has been received, request update every hour
    	if ((!timeReceived && (now-lastRequest > 10*1000)) ||	
    		(now-lastRequest > 3600000UL)){					// request update every hour to keep in sync
           // Request time from controller. 
           Serial.println("requesting time");
           timeReceived = false;
           lastRequest = now;
        // Change display and update sensors every 5 seconds
        if (now-lastDisplay > 5000){
    		lastDisplay = now;
    		gw.request(LCD1_CHILD, V_TEXT, 0); 					// request new values from controller
    		gw.request(LCD2_CHILD, V_TEXT, 0); 					// request new values from controller
    		// change display 
    			if (display_no >= 2){ // wrap for number of different displays for second line
    			display_no = 0;
        // Update display every second
        if (now-lastUpdate > 1000) {
    		lastUpdate = now;
    // This is called when a new time value was received
    void receiveTime(unsigned long controllerTime) {
        Serial.print("Time value received: ");
        setTime(controllerTime); 							// time from controller
        timeReceived = true;
    // This is called when a message is received 
    void incomingMessage(const MyMessage &message) {
    	if (message.type==V_TEXT) {							// Text messages only
         // Write some debug info
         Serial.print("Message: "); Serial.print(message.sensor); Serial.print(", Message: "); Serial.println(message.getString());
    	if (message.sensor == LCD1_CHILD ) {
    		snprintf(lastLCD1, sizeof(lastLCD1), "%16s", message.getString());	// load text into LCD string
    	else if (message.sensor == LCD2_CHILD){
    		snprintf(lastLCD2, sizeof(lastLCD2), "%16s", message.getString());
    void LCD_local_display(void){
    // take car of LCD display information
        char buf[17]; // temp buffer for max 16 char display
        // start with location & time on first line
        snprintf(buf, sizeof buf, "%02d:%02d:%02d %02d-%02d", hour(), minute(), second(), day(), month());
        lcd.setCursor(0, 0);
        lcd.setCursor(0, 1);
        if (display_no == 0){
          lcd.print(lastLCD1); 							// second line is text value from controller
        } else { 										// display == 2

  • Contest Winner

    Oh wow! This just really makes my day. This is something that I've been waiting to be able to do since I discovered Domoticz and MySensors. Great job guys!!! This will really supply us with unlimited possibilites. Thanx again!

  • Plugin Developer

    Will the V_TEXT be able to concatenate text over multiple messages together?

  • Admin

    Good Q @John,

    Do you have any proposal? I'm a bit tired here, only hacky solutions pops up in my head.

  • Hero Member

    @John would be a nice feature you are invited. Probably best to solve it in de sensor code

  • Contest Winner

    Just one idea that pops up in my head. We will be able to send/update authorized RFID code to an RFID connected to MySensors enabled Arduino?

  • Plugin Developer

    @hek @awi
    The only thing i can think of at the moment is to have a message amount + sequence. When sequence is out of order throw away the message. and disregard the following message

    Or start + termination bytes implemented. This byte could identify being a multi message or a single message. A single message has the termination byte set. A multi message starts with a start byte and the last with the termination byte. Problem is lost messages creates strange texts missing pieces.

    Both methods will be able to determine new message because of the "start" byte. But the second proposal would be more error prone because if a message with a start bit is missed it would keep concatenating.

    The first proposal seems to be the most logical one. All though it should be limited so it does not cause the node to go oom. And limit it to the V_TEXT type seems logical

    I wish i had more time so i could help with it, but then i would pick up the MQTT gateway first (for example for battery level reporting) But we are in the middle of about 20 projects... Honored to be be invited, but time does not permit it.

    Or a maybe bit hacky, but i think do-able is instead of putting these start-end bits in the header (to keep it small), sneaky inject them in the V_TEXT. It makes the content payload smaller, but it is multi message which then in the end makes the payload "bigger". All though it would then be possible that the last message only contains a termination byte.

    I have been personally been thinking of sending multi text messages with a start and end character to be able to send longer IR codes around.

  • Hero Member

    @TheoL I don't see a reason why not. V_TEXT is a generic variable. It will depend mainly on the controllers abilities.

  • Contest Winner

    @AWI Thank you for your reply. I have thought about it a bit on my way home from work. When My guests will be leaving again - the weekend after this weekend - I'll start with a simple scene controller for Domoticz. It'll be an easy play ground for the v_text, just an arduino sketch which you and @GizMoCuz already made and some simple bash and lua scripts. Shouldn't take long.

    When that works I'll start the proof of concept for sending valid RFID codes over MySensors to an RFID reader node. I ordered an RFID reader yesterday which was really cheap, about 5 dollar. So not sure if it'll work great.

    My plan is to use an RFID reader as an replacement for the numeric keypad for turning on/off the alarm. I figured that RFID will be easier to use and remember than a pin code.

    In the beginning I will store my valid RFID codes in an file on the filesystem of Domoticz. But maybe in the future I'll create a Node js application with a decent database for that. It's not very wise to store delegate keys like that not encrypted or decoded in a file on a fs.

  • Contest Winner

    @AWI I'm trying to register the sensor to domoticz. Here's the report in the serial monitor

    send: 7-7-0-0 s=255,c=0,t=17,pt=0,l=3,sg=0,st=ok:1.5
    send: 7-7-0-0 s=255,c=3,t=6,pt=1,l=1,sg=0,st=ok:0
    read: 0-0-7 s=255,c=3,t=6,pt=0,l=1,sg=0:M
    sensor started, id=7, parent=0, distance=1
    send: 7-7-0-0 s=255,c=3,t=11,pt=0,l=16,sg=0,st=ok:Domotica Monitor
    send: 7-7-0-0 s=255,c=3,t=12,pt=0,l=3,sg=0,st=ok:1.0
    send: 7-7-0-0 s=0,c=0,t=36,pt=0,l=10,sg=0,st=ok:Databridge
    send: 7-7-0-0 s=0,c=1,t=47,pt=0,l=1,sg=0,st=ok:-
    send: 7-7-0-0 s=255,c=3,t=1,pt=0,l=0,sg=0,st=ok:

    But I can't see the sensor in Domoticz - it's update to the latest stable release. I'm trying to get this to work with a Nokia 5110 LCD display. This sketch will tell me the date/time and outside and inside weather conditions. Did I miss something? Here's the sketch.

     * Room condition display. 
     * This sketch is the Prototype Sketch for testing if we can combine a Nokia 5110 LCD display and MySensors.
     * The goal we're trying to achieve is to use the Nokia 5110 as a display for showing sensor values like:
     * - the current date and time (if we've some I2C pins left we'll hook up an I2C RTC)
     * - the current room temperature
     * - the current room hummidity
     * - the barometric pressure
     * - the outside temperature
     * - etc
    #include <SPI.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_PCD8544.h>
    #include <MySensor.h> // Mysensor network
    #include <Time.h>
    #define TEXT_NODE_CHILD_ID 0
    #define NODE_ID 7 // use a static nodeID for this sensor.
    // uncomment if you are using the DEVELOPMENT version with V_TEXT & V_INFO defined (better to use development MyMessage.h)
    const byte V_TEXT = 47;                  // values taken from development edition MyMessage.h
    const byte S_INFO = 36;
    // Software SPI (slower updates, more flexible pin options):
    // pin 7 - Serial clock out (SCLK)
    // pin 6 - Serial data out (DIN)
    // pin 5 - Data/Command select (D/C)
    // pin 4 - LCD chip select (CS)
    // pin 3 - LCD reset (RST)
    Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);
    MySensor gw;
    // Initialize messages for sensor network
    MyMessage textMsg( 0, V_TEXT );
    boolean timeReceived = false ;
    void setup() {
      Serial.begin( 115200 );
      // initialize 5110 LCD
      // initialize MySensor communication
      gw.begin(incomingMessage, NODE_ID);
      //Send the sensor node sketch version information to the gateway
      gw.sendSketchInfo("Domotica Monitor", "1.0");
      gw.present(TEXT_NODE_CHILD_ID, S_INFO, "Databridge"); 
      // Initializations
      // you can change the contrast around to adapt the display
      // for the best viewing!
    void displayDateAndTime() {
      // text display tests
      // display.setTextColor( WHITE, BLACK ); // 'inverted' text
      display.setTextColor( BLACK ); // 'inverted' text
      display.println("Zo 20-09-2015");
      display.setTextColor( BLACK ); // 'inverted' text
    void loop() {
     // do nothing yet
    // This is called when a new time value was received
    void receiveTime(unsigned long controllerTime) {
      Serial.print("Time value received: ");
      timeReceived = true;
    // This is called when a message is received 
    void incomingMessage(const MyMessage &message) {
      if (message.type==V_TEXT) { 
        // Write some debug info
        Serial.print("Message: "); Serial.print(message.sensor); Serial.print(", Message: "); Serial.println(message.getString());

  • Hero Member

    @TheoL You should use the latest Domoticz beta release. It is a very new (beta) feature. Domoticz can (at the moment) not recognize the S_INFO but will create the sensor when a V_TEXT is sent.

  • Contest Winner

    @AWI Thanx for your quick reply. I'm able to add the sensor node to Domoticz. When I use the JSON url I get an Update OK from Domotoicz. But I can't see an incomming message. I added gw.process() to the main loop. Do I need to update the MySensors gateway as well?

  • Admin

    No, the gateway will forward anything you throw at it.

  • Hero Member

    @TheoL the sketch polls the controller every x seconds. So it should send the update everytime. What value does the text sensor have in the 'device" listing?

  • Contest Winner

    @hek Thanks you for claryfying that. @AWI I'll adjust the code tomorrow. The device doesn't have a value in Domoticz. But it's getting a bit to late at the moment. 😉

  • Contest Winner

    I've gotten it to work. But the version of Domoticz I installed was very unstable. It caused the GUI to stall. At the end I had to burn a new installation on a SD card and had to setup everything from scratch. I have no spare Pi at the moment so I have to postpone this project for a while.

    It's a pitty 'cause I was really looking forward to this project.

  • this is a great project thank you.
    just a quick question is there a way to be able to turn on and off the backlight with text received from domoticz?
    for example if i just send "1" then the back light goes on and "0" for off.


  • Hero Member

    @user1306 you can do anything with the text sent but be aware that this would imply you are making your own (non standard MySensors) protocol. V_TEXT is intended only for information.
    I am the 'misusing' it myself but only where there is no MySensors solution.

  • @AWI
    thank you for the info, i'm a bit new to arduino and my sensors, so i'm not really sure how to do that.
    if possible could you let me know what piece of code i need to be able to do that?


  • Hero Member

    @user1306 This is a part from the routine where I read three values from a V_TEXT value (renamed to V_ORIENTATION) separated by a ";". (I think V_ORIENTATION would be a good addition for MySensors 😉 in addition to V_POSITION but I haven't suggested it officially yet)

    Also be aware that Domoticz only sends the V_TEXT after it has been requested. So you need to send a request(sensor_id, V_TEXT)first .

    #define V_ORIENTATION V_TEXT								// Own (not existing in MySensors protocol) type for orientation (payload = Pitch ; Roll ; Yaw in degrees)
    #define S_ORIENTATION S_INFO								// Yaw = 0 (north)to 360) ; Horizontal = 0 ; 
    			if (message.type==V_ORIENTATION) {
    				char payload[12] ;								// temporary buffer
    				strcpy(payload, message.getString());			// read and copy payload
    				Yaw = atoi(strtok(payload, ";"));				// get variables from payload (; seperated int)
    				Pitch = atoi(strtok(NULL, ";"));
    				Roll = atoi(strtok(NULL, ";"));
    				attachServos(true) ;							// power up servo's
    				servoH.write(map(-constrain(Yaw, -90, 90),-90, 90, 0, 180));		// servo middle 90 deg == 0 deg Yaw 
    				servoV.write(map(Pitch, -90, 90, 0, 180));