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):
    upload-15e45402-6839-4ff9-a32d-9fabbd1f3f35

    "LCD Display" (standard 2x16 char, I2C):
    upload-1fd2549d-5e44-4896-832b-ce642fc2e84c

    start the sketch (end of post). Activated sensor in Domoticz:
    upload-e588beb4-52a2-49ea-ad93-14fc634b99bf

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

    http://192.168.2.20:8080/json.htm?type=command&param=udevice&idx=369&nvalue=0&svalue=I %01 MySensors
    

    and on the LCD
    upload-e907075a-f500-46a2-9fbc-cebb2d3c4107

    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
     PROGRAMMER: AWI
     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 ()
    		
    Special:
    	MySensors - Development (as of sept 2015)
    	
    SUMMARY:
    	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>   						//http://playground.arduino.cc/Code/Time
    #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)
    	gw.send(textMsg.setSensor(LCD2_CHILD).set("-"));		
    
    	// 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.setBacklight(HIGH);
        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;
           gw.requestTime(receiveTime);  
           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 
    		display_no++;
    			if (display_no >= 2){ // wrap for number of different displays for second line
    			display_no = 0;
    			}
    		}
        // Update display every second
        if (now-lastUpdate > 1000) {
    		LCD_local_display();
    		lastUpdate = now;
    		}
    	}
    
    // This is called when a new time value was received
    void receiveTime(unsigned long controllerTime) {
        Serial.print("Time value received: ");
        Serial.println(controllerTime);
        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.print(buf);
        lcd.setCursor(0, 1);
        if (display_no == 0){
          lcd.print(lastLCD1); 							// second line is text value from controller
        } else { 										// display == 2
          lcd.print(lastLCD2);
        }
    }
    

  • 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
      display.begin();
      
      // 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"); 
      gw.send(textMsg.setSensor(TEXT_NODE_CHILD_ID).set("-"));
     
      // Initializations
      gw.requestTime(receiveTime);     
      
      // you can change the contrast around to adapt the display
      // for the best viewing!
      display.setContrast(50);
    
      displayDateAndTime();
    }
    
    void displayDateAndTime() {
      display.clearDisplay();
      // text display tests
      display.setTextSize(1);
      // display.setTextColor( WHITE, BLACK ); // 'inverted' text
      display.setTextColor( BLACK ); // 'inverted' text
      display.setCursor(0,0);
      display.println("Zo 20-09-2015");
      display.setTextColor( BLACK ); // 'inverted' text
      display.setTextSize(2);
      display.setCursor(10,18);
      display.println("10:43");
      display.display();
      delay(2000);
    }
    
    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: ");
      Serial.println(controllerTime);
      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.

    thanks


  • 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?

    thanks


  • 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));
    				}

  • Hero Member

    On special request of @pepov attached a piece of LUA script for Domoticz. This demonstrates how to fill V_TEXT devices from other values so that thes can be displayed on the Text sensor node.

    This special example demonstrates how to fill V_TEXT with weather data from a virtual device connected to Weather Underground. Please search the Domoticz wiki for more information on this special service.

    -- script to read the virtual Weatherstation (Weather Underground) service and send it to "V_TEXT" MySensors devices
    -- Weather Underground values are in 'WUWeer' and 'WUWind'
    
    commandArray = {} ;
    --Weatherstation data:
    sWeatherTemp, sWeatherHumidity, sWeatherUV, sWeatherPressure, sWeatherUV2 = otherdevices_svalues['WUWeer']:match("([^;]+);([^;]+);([^;]+);([^;]+);([^;]+)") ;
    sWeatherTemp = tonumber(sWeatherTemp);
    sWeatherHumidity = tonumber(sWeatherHumidity);
    sWeatherUV = tonumber(sWeatherUV);
    sWeatherPressure = tonumber(sWeatherPressure);
    sWeatherUV2 = tonumber(sWeatherUV2);
    -- print to log 
    print("Weather station: Temperature is " .. sWeatherTemp .. " ");
    print("Weather station: Humidity is " .. sWeatherHumidity .. " ");
    print("Weather station: UV is " .. sWeatherUV .. " ");
    print("Weather station: Pressure is " .. sWeatherPressure .. " ");
    print("Weather station: UV2 is " .. sWeatherUV2 .. " ");
     
    ------------------------------------------------------------------------
     
    --Windmeter data:
    sWindDirectionDegrees, sWindDirection, sWindSpeed, sWindGust, sWindTemperature, sWindFeel = otherdevices_svalues['WUWind']:match("([^;]+);([^;]+);([^;]+);([^;]+);([^;]+);([^;]+)") ;
     
    sWindDirectionDegrees = tonumber(sWindDirectionDegrees);
    sWindDirection = (sWindDirection);
    sWindSpeed = tonumber(sWindSpeed);
    sWindGust = tonumber(sWindGust);
    sWindTemperature = tonumber(sWindTemperature);
    sWindFeel = tonumber(sWindFeel);
     
    print("Windmeter: Winddirection (in degrees) is: " .. sWindDirectionDegrees .. " ");
    print("Windmeter: Winddirection is: " .. sWindDirection .. " ");
    print("Windmeter: Windspeed is: " .. sWindSpeed .. " ");
    print("Windmeter: Windgust is: " .. sWindGust .. " ");
    print("Windmeter: Windtemperature is: " .. sWindTemperature .. " ");
    print("Windmeter: Windfeel is: " .. sWindFeel .. " ");
    
    -- device numbers 725/ 873 and 872 are V_TEXT  
    commandArray[1] = {['UpdateDevice'] = string.format ("725|0|out %4.1f\01 %2d\07 %4d\02\03  ", sWeatherTemp, sWeatherHumidity, sWeatherPressure)}
    commandArray[2] = {['UpdateDevice'] = string.format ("873|0|%2.1f:%3d:%4.1f", sWeatherTemp, sWeatherHumidity, sWeatherPressure)}
    commandArray[3] = {['UpdateDevice'] = string.format ("872|0|%3d:%4.1f:%4.1f:%4.1f:%4.1f", sWindDirectionDegrees, sWindSpeed/10 , sWindGust/10, sWindTemperature, sWindFeel)}
    
    
    return commandArray
    


  • @AWI said:

    evices from other values so that thes can be displayed on the Text sensor node.

    This special example demonstrates how to fill V_TEXT with weather data from a virtual device connected to Weather Underground. Please search the Domoticz wiki for more informati

    Wow Thanks AWI!!!!



  • Does this work with MySensors 2.0? If someone has this running on 2.0, please share the code. 🙂



  • Hi,
    i try to send message but nothing change on LcdDisplay.

    I d'ont undestant what is wrong.

    Can you help me pls.

    send: 49-49-20-0 s=8,c=2,t=47,pt=0,l=0,sg=0,st=ok:
    send: 49-49-20-0 s=9,c=2,t=47,pt=0,l=0,sg=0,st=ok:
    read: 0-20-49 s=9,c=1,t=16,pt=0,l=4,sg=0:test
    send: 49-49-20-0 s=9,c=1,t=16,pt=0,l=4,sg=0,st=ok:test
    send: 49-49-20-0 s=8,c=2,t=47,pt=0,l=0,sg=0,st=ok:
    


  • @NiklasO I have something similar running on MYS 2.0 and can paste the code. I'm using a 4x1 display and using V_VAR-1-4 to send each line over.
    If that's useful to you I can post it.



  • @Qu3Uk said:

    @NiklasO I have something similar running on MYS 2.0 and can paste the code. I'm using a 4x1 display and using V_VAR-1-4 to send each line over.
    If that's useful to you I can post it.

    Yes please. I ported to 2.0 late yesterday and it works ok. I have 4 lines, 20 chars.


  • Hero Member

    @Marc-Olivier-Chaubet Can you post a little more information (the sketch)?

    The text seems to be arriving at the node. So first check if the information comes in on serial (Serial.print(....)).
    And next: is your display working? just print something it in the local sketch.



  • @NiklasO

    Here is it.

    // Enable debug prints to serial monitor
    //#define MY_DEBUG
    
    //#define MY_NODE_ID 200
    #define MY_SENSOR_ID 1
    
    // Enable and select radio type attached
    #define MY_RADIO_NRF24
    //#define MY_RADIO_RFM69
    
    // Enable repeater functionality for this node
    #define MY_REPEATER_FEATURE
    
    // LCD includes
    #include <Wire.h> 
    #include <LiquidCrystal_I2C.h>
    
    // MYS includes
    #include <SPI.h>
    #include <MySensors.h>
    
    #define LCD_ON 1  // GPIO value to write to turn on attached relay
    #define LCD_OFF 0 // GPIO value to write to turn off attached relay
    
    LiquidCrystal_I2C lcd(0x3f, 20, 4); //0x3f is the LCD address.
    String LINE_BLANK = "                    ";
    
    void before() {
    }
    
    void setup() {
      // Set off  LCD module
      lcd.begin (); 
      lcd.backlight();
    
      lcd.setCursor(0, 0); //
      lcd.print("Ready!"); // We expect the controller to remove this from display.
    }
    
    void presentation()
    {
      // Send the sketch version information to the gateway and Controller
      sendSketchInfo("LCD Display", "1.0");
    
      present(MY_SENSOR_ID, S_INFO);
    }
    
    
    void loop()
    {
      // extra processing if required.
    }
    
    void receive(const MyMessage &message) {
      // We only expect one type of message from controller. But we better check anyway.
      if (message.type == V_STATUS) {
        // Use V_STATUS to turn on/off the LCD display
        // if supported by LCD.
      }
    
      // temp string, probably don't need this.
      if (message.type == V_VAR1) {
        writeScreen(0, message.data);
      }
    
      if (message.type == V_VAR2) {
        writeScreen(1, message.data);
      }
    
      if (message.type == V_VAR3) {
        writeScreen(2, message.data);
      }
    
      if (message.type == V_VAR4) {
        writeScreen(3, message.data);
      }
    }
    
    void writeScreen(int line, String text)
    {
      // Trim whitespace from incoming text.
      text.trim();
    
      // Remove anything over 20 char in text.
      if(text.length() > 19)
      {
          text.remove(20);
      }
      
      // Clear the line
      lcd.setCursor(0, line);
      lcd.print(LINE_BLANK);
    
      // Set Line
      lcd.setCursor(0, line);
      lcd.print(text);
    }
    


  • Hi AWI,
    Yes my display is working, i can see the date and "Line 1 - First....."

    I think what i send is not correct....0_o
    This is from the serial monitor

    read: 0-20-49 s=9,c=1,t=16,pt=0,l=4,sg=0:test
    

    Should it be something like this

    read: 0-20-49 s=9,c=1,t=16,pt=0,l=4,sg=0:Line1=test
    

    this is the sketch.

    
    /*
     PROJECT: MySensors / LCD display for text from controller
     PROGRAMMER: AWI
     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 ()
            
    Special:
        MySensors - Development (as of sept 2015)
        
    SUMMARY:
        display time & 2 lines of text from Controller Text sensors
    */
    
    #include <MyMessage.h>
    #include <MySensor.h>                       // Mysensor network
    #include <SPI.h>
    #include <LiquidCrystal_I2C.h>
    #include <Time.h>                           //http://playground.arduino.cc/Code/Time
    #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)
        gw.send(textMsg.setSensor(LCD2_CHILD).set("-"));        
    
        // 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.setBacklight(HIGH);
        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;
           gw.requestTime(receiveTime);  
           lastRequest = now;
            }
        // Change display and update sensors every 5 seconds (default = 5000)
        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 
            display_no++;
                if (display_no >= 2){ // wrap for number of different displays for second line
                display_no = 0;
                }
            }
        // Update display every second
        if (now-lastUpdate > 1000) {
            LCD_local_display();
            lastUpdate = now;
            }
        }
    
    // This is called when a new time value was received
    void receiveTime(unsigned long controllerTime) {
        Serial.print("Time value received: ");
        Serial.println(controllerTime);
        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.print(buf);
        lcd.setCursor(0, 1);
        if (display_no == 0){
          lcd.print(lastLCD1);                          // second line is text value from controller
        } else {                                        // display == 2
          lcd.print(lastLCD2);
        }
    }
    
    

    Thxs


  • Hero Member

    @Marc-Olivier-Chaubet You should be receiving the TEXT value coming from the controller. Is node showing other information on serial?

    // This is called when a message is received 
    void incomingMessage(const MyMessage &message) {
         // Write some debug info
         Serial.print("Message: "); Serial.print(message.sensor); Serial.print(", Message: "); Serial.println(message.getString());
        if (message.type==V_TEXT) {                         // Text messages only
         // Write some debug info
         Serial.print("Text 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());
            }
        } 
    }
    

    In incomingmessage routing add a print statement to show which messages are coming in (see above).



  • Hi,
    I've change this line with "!=" and it work. but i dont undestand why....?

    
    void incomingMessage(const MyMessage &message) {
        if (message.type!=V_TEXT) {                         // Text messages only
    

  • Hero Member

    @Marc-Olivier-Chaubet A closer look at what happens on you seria outputl:
    0_1476200021647_upload-770a6b42-dfb9-43dc-b647-0957e02cc9b8

    • on the first 2 lines there are 2 requests for values from your controller. The "t=47' indicates that the type is V_TEXT.
    • on the the third line you receive a value with payload "test". however the 't=16' indicates that this is a V_TRIPPED value. (see Serial Protocol).

    So there is something completely wrong. What is your controller and does it show the right types of sensors?



  • @Qu3Uk

    thank you very much for sharing your code.
    sorry this might be simple but i'm not sure how do you send text to the display? How do you update V_VAR1 in domoticz?

    thanks



  • This is my test code. Not optimized, just testing. I have just started to play with arduino (got my first ever this month) so I can't say I know what I am doing. 😉 Made som changes in the code below, not tested yet. It compiles, guess that's good. 😉

    I have commented out stuff related to line1 because that is always showing the time and date, in code, from GW/controller. Enable if you want to control all 4 lines from Domoticz.

    Update display by using the domoticz api:
    json.htm?type=command&param=udevice&idx=XXXX&nvalue=0&svalue=Banana
    Replace XXXX with the IDX for each of the 3 lines. You'll see it when adding the 3 text devices in Domoticz. Then use the Event-system in Domoticz to add Lua-script to update the display as example in this thread.

    //Credits: https://forum.mysensors.org/topic/1957/lcd-clock-and-text-sensor-node-with-new-v_text
    
    //Soft signing.
    //#define MY_SIGNING_SOFT
    //#define MY_SIGNING_REQUEST_SIGNATURES
    //#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
    
    #define MY_RADIO_NRF24
    #define MY_REPEATER_FEATURE
    #define MY_DEBUG
    
    #include <TimeLib.h>
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>
    #include <SPI.h>
    #include <MySensors.h>
    
    //char lastLCD1[21] = "Line1"; //Line 1 always showing current time
    char lastLCD2[21] = "Line2";
    char lastLCD3[21] = "Line3";
    char lastLCD4[21] = "Line4";
    
    //20 whitespace characters used to clear your LCD line before printing to it.
    //Change to fit your LCD. Don't forget to change number of chars in the writeScreen function if needed.
    String LINE_BLANK = "                    ";
    
    boolean timeReceived = false ;
    unsigned long lastUpdate = 0, lastRequest = 0, lastDisplay = 0;
    
    //const byte LCD1_CHILD = 1;                          // Child ID for LCD line 1
    const byte LCD2_CHILD = 2;                          // Child ID for LCD line 2
    const byte LCD3_CHILD = 3;                          // Child ID for LCD line 3
    const byte LCD4_CHILD = 4;                          // Child ID for LCD line 4
    
    MyMessage textMsg(0, V_TEXT);
    
    // Initialize display. Google the correct settings for your display.
    // The follwoing setting should work for the recommended display in the MySensors "shop".
    LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
    
    void before() {
      Wire.begin();                                       // I2C.
      lcd.begin(20, 4);                                   // LCD with 20 chars, 4 lines.
      lcd.setBacklight(HIGH);                             // Make sure backlight is on.
      writeScreen(0, "Waiting for GW...");                // Print initial text before contact with GW.                 
    }
    
    void setup(void)
    {
      Serial.begin(115200);                               // Start serial.
      requestTime();                                      // Request time from controller.
    }
    
    void presentation()  {
    
      sendSketchInfo("Domoticz LCD", "1.0");                    // Send the sketch version information to the gateway and Controller
    
      //present(LCD1_CHILD, S_INFO, "LCD_line1");
      //wait(500);
      present(LCD2_CHILD, S_INFO, "LCD_line2");
      wait(500);
      present(LCD3_CHILD, S_INFO, "LCD_line3");
      wait(500);
      present(LCD4_CHILD, S_INFO, "LCD_line4");
      wait(500);
      //send(textMsg.setSensor(LCD1_CHILD).set("-"));      // initialize the V_TEXT at controller for sensor to none (trick for Domoticz)
      send(textMsg.setSensor(LCD2_CHILD).set("-"));
      send(textMsg.setSensor(LCD3_CHILD).set("-"));
      send(textMsg.setSensor(LCD4_CHILD).set("-"));
    }
    
    void loop()     {
      // timer for loop delays
      unsigned long now = millis();
      // 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 from GW every hour to keep in sync
        // Request time from controller.
        Serial.println("Requesting time...");
        timeReceived = false;
        requestTime();
        lastRequest = now;
      }
    
      // Update sensors every 5 seconds
      if (now - lastDisplay > 5000) {
        lastDisplay = now;
        //request(LCD1_CHILD, V_TEXT, 0);                  // request new values from controller
        request(LCD2_CHILD, V_TEXT, 0);                  // request new values from controller
        request(LCD3_CHILD, V_TEXT, 0);                  // request new values from controller
        request(LCD4_CHILD, V_TEXT, 0);                  // request new values from controller
      }
    
      // Update LCD time every second
      if (now - lastUpdate > 1000) {
        LCD_time();
        lastUpdate = now;
      }
    }
    
    // This is called when a message is received
    void receive(const MyMessage &message) {
      if (message.type == V_TEXT) {                       // Text messages only
        Serial.print("Message: "); Serial.print(message.sensor); Serial.print(", Message: "); Serial.println(message.getString());     // Write some debug info
        //if (message.sensor == LCD1_CHILD) {
        //  writeScreen(0, message.data);
        //}
    
    // Don't forget to change "if" to "else if" when controlling all 4 lines:
        if (message.sensor == LCD2_CHILD) {
          writeScreen(1, message.data);
        }
        else if (message.sensor == LCD3_CHILD) {
          writeScreen(2, message.data);
        }
        else if (message.sensor == LCD4_CHILD) {
          writeScreen(3, message.data);
        }
      }
    }
    
    void receiveTime(unsigned long ts) {
      setTime(ts);
      timeReceived = true;
    }
    
    void LCD_time(void) {
      lcd.setCursor(0, 0);
      if (timeReceived) {
        lcd.print(year());
        lcd.print("-");
        printDigits(month());
        lcd.print("-");
        printDigits(day());
        lcd.print("     ");
        printDigits(hour());
        lcd.print(":");
        printDigits(minute());
      } else {
        writeScreen(0, "Waiting for time...");
      }
    }
    
    void printDigits(int digits) {
    //add leading 0 if digit = 0-9
      if (digits < 10)
        lcd.print('0');
      lcd.print(digits);
    }
    
    void writeScreen(int line, String text)
    {
      // Remove anything over 20 char in text.
      if (text.length() > 19)
      {
        text.remove(20);
      }
    
      // Clear the line
      lcd.setCursor(0, line);
      lcd.print(LINE_BLANK);
    
      // Set Line
      lcd.setCursor(0, line);
      lcd.print(text);
    }
    

  • Hero Member

    @user1306 V_VAR1 in Domoticz can not be updated or changed in Domotics (Blockly/ Lua/ Json, etc.). It's can only be used to store and retrieve values from MySensors. You should use V_TEXT as in the original example.



  • thanks guy for the help,
    what i'm trying to do, is send text to the display (16x2) using both lines (dont really need the time on top), and attach a 4 button keypad on it. then have these buttons sends commands (on.off) to Domoticz which will trigger Event and send that data/text back to the display.
    if i manage to figure it out i'll post my code.



  • Is there a limitation in text length? I plan to use a bigger display and want to maybe send strings with 30+ chars. Is it impossible (maybe then split this into two strings) or is it internally seperated in 2 messages (as nrf-payload is 32 byte - 7 byte MySensors-header)?


  • Hero Member

    @Anduril The text length is limited to the maximum payload size. So I guess you need to do some tweaking 😉



  • Re: LCD Clock and Text sensor node with new V_TEXT
    Hello ,
    I have done the same exercise also with the LCD 4*20 and use the same program. It is great.
    It works but only I have the first line with the date.
    The lines 2,3,4 are empty.
    In Domoticz my V_TEXT are created and filled in.
    It seems that I can not read correctly the information LCD_line2, LCD_line3,LCD_line4
    0_1510218378199_Screen Shot 2017-11-09 at 9.56.27 AM.png
    0_1510218403691_Screen Shot 2017-11-09 at 9.55.50 AM.png
    we can see that on the line READ , the text is V_TEXT but nothing is received.
    Why ?
    0_1510218424508_Screen Shot 2017-11-09 at 9.50.27 AM.png

    Thanks


Log in to reply
 

Suggested Topics

73
Online

11.4k
Users

11.1k
Topics

112.7k
Posts