Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. My Project
  3. Scrolling Text sensor node with new V_TEXT

Scrolling Text sensor node with new V_TEXT

Scheduled Pinned Locked Moved My Project
51 Posts 17 Posters 30.1k Views 13 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • gusG Offline
    gusG Offline
    gus
    wrote on last edited by
    #42

    Hi,

    I'm using this fantastic code as well. This is working on 2.0

    Next step for me would be to be able to create an array with more messages, so that the display could cycle thru them.

    /*
     PROJECT: MySensors / Scrolling Text display
     PROGRAMMER: AWI
     DATE: september 12, 2015/ last update: september 12, 2015
     FILE: AWI_scroll_MAX.ino
     LICENSE: Public domain
    
     Hardware: tbd ..Ceech - ATmega328p board w/ NRF24l01
        and MySensors 1.5 ()
            
    Special:
        Need to use MySensors development edition 
        
    SUMMARY:
        3 S_xx devices for scrolling text
        - Displays a scrolling text from a "V_TEXT" variable
        - additional dimmer sensor for controlling display brightness
        - 'Alarm' switch. If "On", overrides the text display to display ALARM message
        - You can also input messages from the Serial monitor (testing)
        Uses excellent MD_MAX72XX library 
     Remarks:
        Fixed node-id
    */
    
    
    #include <MD_Parola.h>
    #define MY_RADIO_NRF24
    
    // Enable repeater functionality for this node
    #define MY_REPEATER_FEATURE
    
    
    
    // Use the MD_MAX72XX library to scroll text on the display with the use of the callback function 
    // to control what is scrolled on the display text.
    // You need to set the used display in the library MD_MAX72XX.h
    // User can enter text on the serial monitor and this will display as a
    // Speed for the display is controlled by a pot on SPEED_IN analog in.
    #include <MD_MAX72xx.h>                     // multipurpose library for MAX72xx diaplay driver  https://parola.codeplex.com/
    #include <MySensors.h>                       // Mysensor network
    #include <SPI.h>
    #include <Time.h>                           //http://playground.arduino.cc/Code/Time
    #include <TimeLib.h>
    #define USE_POT_CONTROL 0                   // enable Scroll speed  potentiometer
    #define PRINT_CALLBACK  1
    
    // Macro to simplify serial print
    #define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
    
    // Define the number of devices we have in the chain and the hardware interface
    // need to be adapted to your setup
    const int MAX_DEVICES = 2 ;                 // number of 8x8 displays
    const int CLK_PIN = 7 ;                     // SPI like clock
    const int DATA_PIN = 8 ;                    // SPI like data
    const int CS_PIN = 6 ;                      // SPI like select
    
    // Parola is able to use SPI hardware interface, not testted in combination with MySensors
    // MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
    // now use Arbitrary pins
    MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); // instantiate one display chain
    
    // Scrolling parameters, you can attach normal potentiometer to A5, Vcc, Gnd
    #if USE_POT_CONTROL
    const int SPEED_IN = A5 ;
    #else
    const int SCROLL_DELAY = 20 ;               // in milliseconds
    #endif // USE_POT_CONTROL
    
    const int CHAR_SPACING = 1 ;                // pixels between characters
    
    // MySensors constants & variables
    //const byte nodeId = 51 ;                    // MySensors fixed node id
    const byte messageCHILD = 8 ;               // Text from ControllerLCD
    const byte brightnessChild = 9 ;            // Brightness of display
    const byte alarmChild = 10 ;                // Display Alarm text (overrides normal text)
    boolean timeReceived = false ;              // Flag to indicate time received
    // Display constants & variables
    byte textBrightness = 1 ;                   // brightness of display (between 0 - MAX_INTENSITY (0xF)
    byte textOnOff = false ;                     // textOnOff = ! shutdown
    boolean textAlarm = false ;                 // Alarm (switch S_BINARY)
    // Global message buffers shared by MySensors and Scrolling functions
    const int BUF_SIZE = 25 ;                   // max payload for MySensors(NRF24l01)
    char curMessage[BUF_SIZE];                  // current displayed message
    char newMessage[BUF_SIZE];                  // next message to be displayed if available
    bool newMessageAvailable = false ;          // new message available flag
    uint16_t    scrollDelay;                    // in milliseconds
    
    // *** Definition and initialisation
    // define the MySensor network (1.5)
    // Initialize messages for sensor network
    
    MyMessage textMsg(messageCHILD, V_TEXT);    // message for Sending Text to Controller
    
    
    /* MD_MAX72XX functions: can be found in the documentation for the library,
     * no need to customtize callback & scroll routines (unless you want to...)
    */
    uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
    // Callback function for data that is required for scrolling into the display
    {
      static char       *p = curMessage;
      static uint8_t    state = 0;
      static uint8_t    curLen, showLen;
      static uint8_t    cBuf[8];
      uint8_t colData;
    
      // finite state machine to control what we do on the callback
      switch(state)
      {
        case 0: // Load the next character from the font table
          showLen = mx.getChar(*p++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
          curLen = 0;
          state++;
    
          // if we reached end of message, reset the message pointer
          if (*p == '\0')
          {
            p = curMessage;         // reset the pointer to start of message
            if (newMessageAvailable)    // there is a new message waiting
            {
              strcpy(curMessage, newMessage);   // copy it in
              newMessageAvailable = false;
            }
          }
          // !! deliberately fall through to next state to start displaying
    
        case 1: // display the next part of the character
          colData = cBuf[curLen++];
          if (curLen == showLen)                // end of character insert interchar space
          {
            showLen = CHAR_SPACING;
            curLen = 0;
            state = 2;
          }
          break;
    
        case 2: // display inter-character spacing (blank column)
          colData = 0;
          curLen++;
          if (curLen == showLen)
            state = 0;
          break;
    
        default:
          state = 0;
      }
    
      return(colData);
    }
    
    // Callback (not used here)
    void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col){
    // Callback function for data that is being scrolled off the display
    #if PRINT_CALLBACK
        Serial.print("\n cb ");
        Serial.print(dev);
        Serial.print(' ');
        Serial.print(t);
        Serial.print(' ');
        Serial.println(col);
    #endif
    }
    
    // non-blocking text display to be used in loop (call frequently)
    void scrollText(void){
        static uint32_t prevTime = 0;
        if (millis()-prevTime >= scrollDelay){                  // Is it time to scroll the text?
            mx.transform(MD_MAX72XX::TSL);                      // scroll along - the callback will load all the data
            prevTime = millis();                                // starting point for next time
            }
        }
    
    // sets the scroll delay (read from potentiometer if enabled)
    uint16_t getScrollDelay(void){
    #if USE_POT_CONTROL
        uint16_t t = analogRead(SPEED_IN);
        t = map(t, 0, 1023, 25, 250);
        return(t);
    #else
        return(SCROLL_DELAY);
    #endif
        }
    
    void setup(){
        // set up the display first
        mx.begin();                                             // initialize display chain                 
        mx.setShiftDataInCallback(scrollDataSource);            // define function to get the scrolldata (returned as int8)
        //mx.setShiftDataOutCallback(scrollDataSink);           // not used
        mx.control(MD_MAX72XX::INTENSITY, 0x01);
    #if USE_POT_CONTROL                                         // initialize speed potentiometer if enabled
        pinMode(SPEED_IN, INPUT);
    #else
        scrollDelay = SCROLL_DELAY;
    #endif
    
        strcpy(curMessage, "I \x03 MySensors ");                // first message on display
        //newMessage[0] = '\0';                                   // new message initialized to empty RE This is not working....
        // Setup MySensors 
       //Serial in Sensor network = 115200
        //Send the sensor node sketch version information to the gateway
    
    } 
    
    void presentation() {
    
        sendSketchInfo("Scrollo small 52", "1.0");
        present(messageCHILD, S_INFO, "Text line Scroll");   // new S_type 20150905 (not know by domoticz)
        present(alarmChild, S_BINARY, "Alarm display");      // to display alarm text
        present(brightnessChild, S_DIMMER, "Text brightness"); // new S_type 20150905 (not know by domoticz)
        //send(textMsg.set("-"));                            // initialize the V_TEXT at controller for sensor to none (trick for Domoticz)
        request(messageCHILD, V_TEXT, 0);                    // request value from controller
        // Initializations
        requestTime();                            // get the time from controller (handled by receiveTime)
        }
    
    // loop only uses non-blocking functions
    void loop() {
        static unsigned long lastUpdate ;                       // Static hold the last update time
        unsigned long now = millis();
        scrollDelay = getScrollDelay();                         // update scroll delay from potentiometer
        //readSerial();
        // Check for new conditions & ask for new information from controller every 10 seconds
        if (now-lastUpdate > 10000){
            if (textAlarm){                                     // if alarmstatus: override all text and set max intensity
                strcpy(curMessage, "   ALARM   ");
                mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY);   // set current brightness
                mx.control(MD_MAX72XX::SHUTDOWN, false) ;
            } else {                                            // standard (non Alarm actions)
                mx.control(MD_MAX72XX::INTENSITY, textBrightness);  // set current brightness
                mx.control(MD_MAX72XX::SHUTDOWN, textOnOff) ;
                request(messageCHILD, V_TEXT, 0);                // request new value from controller
            }
            lastUpdate = now;
        }
        scrollText();
    }
     
    // 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 receive(const MyMessage &message) {
        Serial.print("Message: "); Serial.print(message.sensor); Serial.print(", Message: "); Serial.println(message.getString());
        if (message.sensor == messageCHILD){
            if (message.type==V_TEXT) {                     // Text content
            strcpy(newMessage, message.getString());        // copy it in
                newMessageAvailable = true ;
            }
        } else if (message.sensor == alarmChild) {
            if (message.type==V_STATUS) {                   // True/ false content
                textAlarm = message.getBool()?true:false ;  // set alarmflag
                Serial.print("TextAlarm: ");
                Serial.println(textAlarm);
            }
        } else if (message.sensor == brightnessChild){
            if (message.type==V_PERCENTAGE) {               // Level 0..100  content
                textBrightness = map(message.getInt(),0, 100, 0, MAX_INTENSITY ) ;  // map to brightnesslevel 
                Serial.print("TextBrightness: ");
                Serial.println(textBrightness);
            } else if (message.type==V_STATUS) {            // Display on/off
                textOnOff = message.getBool()?false:true ;      // set shutdown/ !on/off
                Serial.print("Text on/off: ");
                Serial.println(textOnOff);
            }
        }
    }
    
        
    // Testing purposes: input routine character buffer. Reads serial characters in buffer newMessage.
    // sets flag newMessageAvailable to true if completed
    void readSerial(void)
    {
      static uint8_t    putIndex = 0;
    
      while (Serial.available())
      {
        newMessage[putIndex] = (char)Serial.read();
        if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
        {
          // put in a message separator and end the string
          newMessage[putIndex++] = ' ';
          newMessage[putIndex] = '\0';
          // restart the index for next filling spree and flag we have a message waiting
          putIndex = 0;
          newMessageAvailable = true;
        }
        else
          // Just save the next char in next location
          newMessage[putIndex++];
      }
    }
    
    korttomaK 1 Reply Last reply
    0
    • gusG gus

      Hi,

      I'm using this fantastic code as well. This is working on 2.0

      Next step for me would be to be able to create an array with more messages, so that the display could cycle thru them.

      /*
       PROJECT: MySensors / Scrolling Text display
       PROGRAMMER: AWI
       DATE: september 12, 2015/ last update: september 12, 2015
       FILE: AWI_scroll_MAX.ino
       LICENSE: Public domain
      
       Hardware: tbd ..Ceech - ATmega328p board w/ NRF24l01
          and MySensors 1.5 ()
              
      Special:
          Need to use MySensors development edition 
          
      SUMMARY:
          3 S_xx devices for scrolling text
          - Displays a scrolling text from a "V_TEXT" variable
          - additional dimmer sensor for controlling display brightness
          - 'Alarm' switch. If "On", overrides the text display to display ALARM message
          - You can also input messages from the Serial monitor (testing)
          Uses excellent MD_MAX72XX library 
       Remarks:
          Fixed node-id
      */
      
      
      #include <MD_Parola.h>
      #define MY_RADIO_NRF24
      
      // Enable repeater functionality for this node
      #define MY_REPEATER_FEATURE
      
      
      
      // Use the MD_MAX72XX library to scroll text on the display with the use of the callback function 
      // to control what is scrolled on the display text.
      // You need to set the used display in the library MD_MAX72XX.h
      // User can enter text on the serial monitor and this will display as a
      // Speed for the display is controlled by a pot on SPEED_IN analog in.
      #include <MD_MAX72xx.h>                     // multipurpose library for MAX72xx diaplay driver  https://parola.codeplex.com/
      #include <MySensors.h>                       // Mysensor network
      #include <SPI.h>
      #include <Time.h>                           //http://playground.arduino.cc/Code/Time
      #include <TimeLib.h>
      #define USE_POT_CONTROL 0                   // enable Scroll speed  potentiometer
      #define PRINT_CALLBACK  1
      
      // Macro to simplify serial print
      #define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
      
      // Define the number of devices we have in the chain and the hardware interface
      // need to be adapted to your setup
      const int MAX_DEVICES = 2 ;                 // number of 8x8 displays
      const int CLK_PIN = 7 ;                     // SPI like clock
      const int DATA_PIN = 8 ;                    // SPI like data
      const int CS_PIN = 6 ;                      // SPI like select
      
      // Parola is able to use SPI hardware interface, not testted in combination with MySensors
      // MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
      // now use Arbitrary pins
      MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); // instantiate one display chain
      
      // Scrolling parameters, you can attach normal potentiometer to A5, Vcc, Gnd
      #if USE_POT_CONTROL
      const int SPEED_IN = A5 ;
      #else
      const int SCROLL_DELAY = 20 ;               // in milliseconds
      #endif // USE_POT_CONTROL
      
      const int CHAR_SPACING = 1 ;                // pixels between characters
      
      // MySensors constants & variables
      //const byte nodeId = 51 ;                    // MySensors fixed node id
      const byte messageCHILD = 8 ;               // Text from ControllerLCD
      const byte brightnessChild = 9 ;            // Brightness of display
      const byte alarmChild = 10 ;                // Display Alarm text (overrides normal text)
      boolean timeReceived = false ;              // Flag to indicate time received
      // Display constants & variables
      byte textBrightness = 1 ;                   // brightness of display (between 0 - MAX_INTENSITY (0xF)
      byte textOnOff = false ;                     // textOnOff = ! shutdown
      boolean textAlarm = false ;                 // Alarm (switch S_BINARY)
      // Global message buffers shared by MySensors and Scrolling functions
      const int BUF_SIZE = 25 ;                   // max payload for MySensors(NRF24l01)
      char curMessage[BUF_SIZE];                  // current displayed message
      char newMessage[BUF_SIZE];                  // next message to be displayed if available
      bool newMessageAvailable = false ;          // new message available flag
      uint16_t    scrollDelay;                    // in milliseconds
      
      // *** Definition and initialisation
      // define the MySensor network (1.5)
      // Initialize messages for sensor network
      
      MyMessage textMsg(messageCHILD, V_TEXT);    // message for Sending Text to Controller
      
      
      /* MD_MAX72XX functions: can be found in the documentation for the library,
       * no need to customtize callback & scroll routines (unless you want to...)
      */
      uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
      // Callback function for data that is required for scrolling into the display
      {
        static char       *p = curMessage;
        static uint8_t    state = 0;
        static uint8_t    curLen, showLen;
        static uint8_t    cBuf[8];
        uint8_t colData;
      
        // finite state machine to control what we do on the callback
        switch(state)
        {
          case 0: // Load the next character from the font table
            showLen = mx.getChar(*p++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
            curLen = 0;
            state++;
      
            // if we reached end of message, reset the message pointer
            if (*p == '\0')
            {
              p = curMessage;         // reset the pointer to start of message
              if (newMessageAvailable)    // there is a new message waiting
              {
                strcpy(curMessage, newMessage);   // copy it in
                newMessageAvailable = false;
              }
            }
            // !! deliberately fall through to next state to start displaying
      
          case 1: // display the next part of the character
            colData = cBuf[curLen++];
            if (curLen == showLen)                // end of character insert interchar space
            {
              showLen = CHAR_SPACING;
              curLen = 0;
              state = 2;
            }
            break;
      
          case 2: // display inter-character spacing (blank column)
            colData = 0;
            curLen++;
            if (curLen == showLen)
              state = 0;
            break;
      
          default:
            state = 0;
        }
      
        return(colData);
      }
      
      // Callback (not used here)
      void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col){
      // Callback function for data that is being scrolled off the display
      #if PRINT_CALLBACK
          Serial.print("\n cb ");
          Serial.print(dev);
          Serial.print(' ');
          Serial.print(t);
          Serial.print(' ');
          Serial.println(col);
      #endif
      }
      
      // non-blocking text display to be used in loop (call frequently)
      void scrollText(void){
          static uint32_t prevTime = 0;
          if (millis()-prevTime >= scrollDelay){                  // Is it time to scroll the text?
              mx.transform(MD_MAX72XX::TSL);                      // scroll along - the callback will load all the data
              prevTime = millis();                                // starting point for next time
              }
          }
      
      // sets the scroll delay (read from potentiometer if enabled)
      uint16_t getScrollDelay(void){
      #if USE_POT_CONTROL
          uint16_t t = analogRead(SPEED_IN);
          t = map(t, 0, 1023, 25, 250);
          return(t);
      #else
          return(SCROLL_DELAY);
      #endif
          }
      
      void setup(){
          // set up the display first
          mx.begin();                                             // initialize display chain                 
          mx.setShiftDataInCallback(scrollDataSource);            // define function to get the scrolldata (returned as int8)
          //mx.setShiftDataOutCallback(scrollDataSink);           // not used
          mx.control(MD_MAX72XX::INTENSITY, 0x01);
      #if USE_POT_CONTROL                                         // initialize speed potentiometer if enabled
          pinMode(SPEED_IN, INPUT);
      #else
          scrollDelay = SCROLL_DELAY;
      #endif
      
          strcpy(curMessage, "I \x03 MySensors ");                // first message on display
          //newMessage[0] = '\0';                                   // new message initialized to empty RE This is not working....
          // Setup MySensors 
         //Serial in Sensor network = 115200
          //Send the sensor node sketch version information to the gateway
      
      } 
      
      void presentation() {
      
          sendSketchInfo("Scrollo small 52", "1.0");
          present(messageCHILD, S_INFO, "Text line Scroll");   // new S_type 20150905 (not know by domoticz)
          present(alarmChild, S_BINARY, "Alarm display");      // to display alarm text
          present(brightnessChild, S_DIMMER, "Text brightness"); // new S_type 20150905 (not know by domoticz)
          //send(textMsg.set("-"));                            // initialize the V_TEXT at controller for sensor to none (trick for Domoticz)
          request(messageCHILD, V_TEXT, 0);                    // request value from controller
          // Initializations
          requestTime();                            // get the time from controller (handled by receiveTime)
          }
      
      // loop only uses non-blocking functions
      void loop() {
          static unsigned long lastUpdate ;                       // Static hold the last update time
          unsigned long now = millis();
          scrollDelay = getScrollDelay();                         // update scroll delay from potentiometer
          //readSerial();
          // Check for new conditions & ask for new information from controller every 10 seconds
          if (now-lastUpdate > 10000){
              if (textAlarm){                                     // if alarmstatus: override all text and set max intensity
                  strcpy(curMessage, "   ALARM   ");
                  mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY);   // set current brightness
                  mx.control(MD_MAX72XX::SHUTDOWN, false) ;
              } else {                                            // standard (non Alarm actions)
                  mx.control(MD_MAX72XX::INTENSITY, textBrightness);  // set current brightness
                  mx.control(MD_MAX72XX::SHUTDOWN, textOnOff) ;
                  request(messageCHILD, V_TEXT, 0);                // request new value from controller
              }
              lastUpdate = now;
          }
          scrollText();
      }
       
      // 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 receive(const MyMessage &message) {
          Serial.print("Message: "); Serial.print(message.sensor); Serial.print(", Message: "); Serial.println(message.getString());
          if (message.sensor == messageCHILD){
              if (message.type==V_TEXT) {                     // Text content
              strcpy(newMessage, message.getString());        // copy it in
                  newMessageAvailable = true ;
              }
          } else if (message.sensor == alarmChild) {
              if (message.type==V_STATUS) {                   // True/ false content
                  textAlarm = message.getBool()?true:false ;  // set alarmflag
                  Serial.print("TextAlarm: ");
                  Serial.println(textAlarm);
              }
          } else if (message.sensor == brightnessChild){
              if (message.type==V_PERCENTAGE) {               // Level 0..100  content
                  textBrightness = map(message.getInt(),0, 100, 0, MAX_INTENSITY ) ;  // map to brightnesslevel 
                  Serial.print("TextBrightness: ");
                  Serial.println(textBrightness);
              } else if (message.type==V_STATUS) {            // Display on/off
                  textOnOff = message.getBool()?false:true ;      // set shutdown/ !on/off
                  Serial.print("Text on/off: ");
                  Serial.println(textOnOff);
              }
          }
      }
      
          
      // Testing purposes: input routine character buffer. Reads serial characters in buffer newMessage.
      // sets flag newMessageAvailable to true if completed
      void readSerial(void)
      {
        static uint8_t    putIndex = 0;
      
        while (Serial.available())
        {
          newMessage[putIndex] = (char)Serial.read();
          if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
          {
            // put in a message separator and end the string
            newMessage[putIndex++] = ' ';
            newMessage[putIndex] = '\0';
            // restart the index for next filling spree and flag we have a message waiting
            putIndex = 0;
            newMessageAvailable = true;
          }
          else
            // Just save the next char in next location
            newMessage[putIndex++];
        }
      }
      
      korttomaK Offline
      korttomaK Offline
      korttoma
      Hero Member
      wrote on last edited by
      #43

      @gus you beat me to it, nice job!

      Sorry @Orkspalter I forgot yesterday but I'm sure the one @gus posted is quite similar.

      Is there anyone out there using this setup that have a sketch that can handle scandinavian letters (å, ä, ö). I just get gibberish instead of the letters.

      • Tomas
      korttomaK 1 Reply Last reply
      0
      • korttomaK korttoma

        @gus you beat me to it, nice job!

        Sorry @Orkspalter I forgot yesterday but I'm sure the one @gus posted is quite similar.

        Is there anyone out there using this setup that have a sketch that can handle scandinavian letters (å, ä, ö). I just get gibberish instead of the letters.

        korttomaK Offline
        korttomaK Offline
        korttoma
        Hero Member
        wrote on last edited by
        #44

        @korttoma here is the sketch I'm using, probably quite similar to the one @gus shared

        /*
         PROJECT: MySensors / Scrolling Text display
         PROGRAMMER: AWI
         DATE: september 12, 2015/ last update: september 12, 2015
         FILE: AWI_scroll_MAX.ino
         LICENSE: Public domain
        
         Hardware: tbd ..Ceech - ATmega328p board w/ NRF24l01
            and MySensors 1.5 ()
                
        Special:
            Need to use MySensors development edition 
            
        SUMMARY:
            3 S_xx devices for scrolling text
            - Displays a scrolling text from a "V_TEXT" variable
            - additional dimmer sensor for controlling display brightness
            - 'Alarm' switch. If "On", overrides the text display to display ALARM message
            - You can also input messages from the Serial monitor (testing)
            Uses excellent MD_MAX72XX library 
         Remarks:
            Fixed node-id
        */
        
        // Use the MD_MAX72XX library to scroll text on the display with the use of the callback function 
        // to control what is scrolled on the display text.
        // You need to set the used display in the library MD_MAX72XX.h
        // User can enter text on the serial monitor and this will display as a
        // Speed for the display is controlled by a pot on SPEED_IN analog in.
        
        #define MY_DEBUG 
        #define MY_BAUD_RATE  9600
        #define MY_RADIO_NRF24
        
        #define MY_NODE_ID  20
        #define SN "Scrolling Text"
        #define SV "2.1"
        #include <MyConfig.h>
        #include <MySensors.h>
        #include <MD_MAX72xx.h>                     // multipurpose library for MAX72xx diaplay driver  https://parola.codeplex.com/
        #include <SPI.h>
        #include <Time.h>                           //http://playground.arduino.cc/Code/Time
        #define USE_POT_CONTROL 0                   // enable Scroll speed  potentiometer
        #define PRINT_CALLBACK  1
        
        // Macro to simplify serial print
        #define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
        
        // Define the number of devices we have in the chain and the hardware interface
        // need to be adapted to your setup
        const int MAX_DEVICES = 8 ;                 // number of 8x8 displays
        const int CLK_PIN = 7 ;                     // SPI like clock
        const int DATA_PIN = 8 ;                    // SPI like data
        const int CS_PIN = 6 ;                      // SPI like select
        
        // Parola is able to use SPI hardware interface, not testted in combination with MySensors
        // MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
        // now use Arbitrary pins
        MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); // instantiate one display chain
        
        // Scrolling parameters, you can attach normal potentiometer to A5, Vcc, Gnd
        #if USE_POT_CONTROL
        const int SPEED_IN = A5 ;
        #else
        const int SCROLL_DELAY = 60 ;               // in milliseconds
        #endif // USE_POT_CONTROL
        
        const int CHAR_SPACING = 1 ;                // pixels between characters
        
        // MySensors constants & variables
        const byte messageCHILD = 8 ;               // Text from ControllerLCD
        const byte brightnessChild = 9 ;            // Brightness of display
        const byte alarmChild = 10 ;                // Display Alarm text (overrides normal text)
        boolean timeReceived = false ;              // Flag to indicate time received
        // Display constants & variables
        byte textBrightness = 1 ;                   // brightness of display (between 0 - MAX_INTENSITY (0xF)
        byte textOnOff = false ;                     // textOnOff = ! shutdown
        boolean textAlarm = false ;                 // Alarm (switch S_BINARY)
        // Global message buffers shared by MySensors and Scrolling functions
        const int BUF_SIZE = 25 ;                   // max payload for MySensors(NRF24l01)
        char curMessage[BUF_SIZE];                  // current displayed message
        char newMessage[BUF_SIZE];                  // next message to be displayed if available
        bool newMessageAvailable = false ;          // new message available flag
        uint16_t    scrollDelay;                    // in milliseconds
        
        // *** Definition and initialisation
        // define the MySensor network (1.5)
         
        // Initialize messages for sensor network
        MyMessage textMsg(messageCHILD, V_TEXT);    // message for Sending Text to Controller
        
        
        void presentation()  
        { 
         // Send the sketch version information to the gateway and Controller
          
          sendSketchInfo(SN, SV);
          // Register all sensors to gateway (they will be created as child devices)
           present(messageCHILD, S_INFO, "Text line Scroll");   // new S_type 20150905 (not know by domoticz)
           wait(200);
           present(alarmChild, S_BINARY, "Alarm display");      // to display alarm text
           wait(200);
           present(brightnessChild, S_DIMMER, "Text brightness"); // new S_type 20150905 (not know by domoticz)
           //gw.send(textMsg.set("-"));                            // initialize the V_TEXT at controller for sensor to none (trick for Domoticz)
           wait(200);
           request(messageCHILD, V_TEXT, 0);                    // request value from controller
            // Initializations
           wait(200);
           requestTime(receiveTime);                            // get the time from controller (handled by receiveTime)
           
           wait(200);
        
          
        }
        
        /* MD_MAX72XX functions: can be found in the documentation for the library,
         * no need to customtize callback & scroll routines (unless you want to...)
        */
        uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
        // Callback function for data that is required for scrolling into the display
        {
          static char       *p = curMessage;
          static uint8_t    state = 0;
          static uint8_t    curLen, showLen;
          static uint8_t    cBuf[8];
          uint8_t colData;
        
          // finite state machine to control what we do on the callback
          switch(state)
          {
            case 0: // Load the next character from the font table
              showLen = mx.getChar(*p++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
              curLen = 0;
              state++;
        
              // if we reached end of message, reset the message pointer
              if (*p == '\0')
              {
                p = curMessage;         // reset the pointer to start of message
                if (newMessageAvailable)    // there is a new message waiting
                {
                  strcpy(curMessage, newMessage);   // copy it in
                  newMessageAvailable = false;
                }
              }
              // !! deliberately fall through to next state to start displaying
        
            case 1: // display the next part of the character
              colData = cBuf[curLen++];
              if (curLen == showLen)                // end of character insert interchar space
              {
                showLen = CHAR_SPACING;
                curLen = 0;
                state = 2;
              }
              break;
        
            case 2: // display inter-character spacing (blank column)
              colData = 0;
              curLen++;
              if (curLen == showLen)
                state = 0;
              break;
        
            default:
              state = 0;
          }
        
          return(colData);
        }
        
        // Callback (not used here)
        void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col){
        // Callback function for data that is being scrolled off the display
        #if PRINT_CALLBACK
            Serial.print("\n cb ");
            Serial.print(dev);
            Serial.print(' ');
            Serial.print(t);
            Serial.print(' ');
            Serial.println(col);
        #endif
        }
        
        // non-blocking text display to be used in loop (call frequently)
        void scrollText(void){
            static uint32_t prevTime = 0;
            if (millis()-prevTime >= scrollDelay){                  // Is it time to scroll the text?
                mx.transform(MD_MAX72XX::TSL);                      // scroll along - the callback will load all the data
                prevTime = millis();                                // starting point for next time
                }
            }
        
        // sets the scroll delay (read from potentiometer if enabled)
        uint16_t getScrollDelay(void){
        #if USE_POT_CONTROL
            uint16_t t = analogRead(SPEED_IN);
            t = map(t, 0, 1023, 25, 250);
            return(t);
        #else
            return(SCROLL_DELAY);
        #endif
            }
        
        void setup(){
            // set up the display first
            mx.begin();                                             // initialize display chain                 
            mx.setShiftDataInCallback(scrollDataSource);            // define function to get the scrolldata (returned as int8)
            //mx.setShiftDataOutCallback(scrollDataSink);           // not used
            mx.control(MD_MAX72XX::INTENSITY, 0x01);
        #if USE_POT_CONTROL                                         // initialize speed potentiometer if enabled
            pinMode(SPEED_IN, INPUT);
        #else
            scrollDelay = SCROLL_DELAY;
        #endif
        
            strcpy(curMessage, "HEJ ARON      ");                // first message on display
            newMessage[0] = '\0';                                   // new message initialized to empty
            // Setup MySensors 
           //Serial in Sensor network = 115200
        }    
           
        
        // loop only uses non-blocking functions
        void loop() {
            static unsigned long lastUpdate ;                       // Static hold the last update time
            unsigned long now = millis();
            scrollDelay = getScrollDelay();                         // update scroll delay from potentiometer
            readSerial();
            // Check for new conditions & ask for new information from controller every 10 seconds
            if (now-lastUpdate > 10000){
                if (textAlarm){                                     // if alarmstatus: override all text and set max intensity
                    strcpy(curMessage, "   ALARM   ");
                    mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY);   // set current brightness
                    mx.control(MD_MAX72XX::SHUTDOWN, false) ;
                } else {                                            // standard (non Alarm actions)
                    mx.control(MD_MAX72XX::INTENSITY, textBrightness);  // set current brightness
                    mx.control(MD_MAX72XX::SHUTDOWN, textOnOff) ;
                    request(messageCHILD, V_TEXT, 0);                // request new value from controller
                }
                lastUpdate = now;
            }
            scrollText();
        }
         
        // 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 receive(const MyMessage &message) {
            Serial.print("Message: "); Serial.print(message.sensor); Serial.print(", Message: "); Serial.println(message.getString());
            if (message.sensor == messageCHILD){
                if (message.type==V_TEXT) {                     // Text content
                strcpy(newMessage, message.getString());        // copy it in
                    newMessageAvailable = true ;
                }
            } else if (message.sensor == alarmChild) {
                if (message.type==V_STATUS) {                   // True/ false content
                    textAlarm = message.getBool()?true:false ;  // set alarmflag
                    Serial.print("TextAlarm: ");
                    Serial.println(textAlarm);
                }
            } else if (message.sensor == brightnessChild){
                if (message.type==V_PERCENTAGE) {               // Level 0..100  content
                    int IncomingBrightness = message.getInt();
                    if (IncomingBrightness == 0) {
                      textOnOff = true;
                    }else {
                      textOnOff = false;
                      textBrightness = map(message.getInt(),0, 100, 0, MAX_INTENSITY ) ;  // map to brightnesslevel 
                    Serial.print("TextBrightness: ");
                    Serial.println(textBrightness);
                    }
                               
                } else if (message.type==V_STATUS) {            // Display on/off
                    textOnOff = message.getBool()?false:true ;      // set shutdown/ !on/off
                    Serial.print("Text on/off: ");
                    Serial.println(textOnOff);
                }
            }
        }
        
            
        // Testing purposes: input routine character buffer. Reads serial characters in buffer newMessage.
        // sets flag newMessageAvailable to true if completed
        void readSerial(void)
        {
          static uint8_t    putIndex = 0;
        
          while (Serial.available())
          {
            newMessage[putIndex] = (char)Serial.read();
            if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE-3)) // end of message character or full buffer
            {
              // put in a message separator and end the string
              newMessage[putIndex++] = ' ';
              newMessage[putIndex] = '\0';
              // restart the index for next filling spree and flag we have a message waiting
              putIndex = 0;
              newMessageAvailable = true;
            }
            else
              // Just save the next char in next location
              newMessage[putIndex++];
          }
        }
        
        
        
        • Tomas
        1 Reply Last reply
        0
        • korttomaK Offline
          korttomaK Offline
          korttoma
          Hero Member
          wrote on last edited by
          #45

          Anybody have an example where this setup shows the time while there is no message to scroll?

          • Tomas
          A 1 Reply Last reply
          0
          • korttomaK korttoma

            Anybody have an example where this setup shows the time while there is no message to scroll?

            A Offline
            A Offline
            artur
            wrote on last edited by
            #46

            @korttoma

            Here are found the blank, you need to check how it works

            /*
              PROJECT: MySensors / Scrolling Text display
              PROGRAMMER: AWI
              DATE: september 12, 2015/ last update: september 12, 2015
              FILE: AWI_scroll_MAX.ino
              LICENSE: Public domain
            
              Hardware: tbd ..Ceech - ATmega328p board w/ NRF24l01
                and MySensors 1.5 ()
            
              Special:
                Need to use MySensors development edition
            
              SUMMARY:
                3 S_xx devices for scrolling text
                - Displays a scrolling text from a "V_TEXT" variable
                - additional dimmer sensor for controlling display brightness
                - 'Alarm' switch. If "On", overrides the text display to display ALARM message
                - You can also input messages from the Serial monitor (testing)
                Uses excellent MD_MAX72XX library
              Remarks:
                Fixed node-id
            */
            // Enable debug prints to serial monitor
            #define MY_DEBUG
            
            // Enable and select radio type attached
            #define MY_RADIO_NRF24
            //#define MY_RADIO_RFM69
            
            #define  DEBUG 0   // Enable or disable (default) debugging output
            
            // Use the MD_MAX72XX library to scroll text on the display with the use of the callback function
            // to control what is scrolled on the display text.
            // You need to set the used display in the library MD_MAX72XX.h
            // User can enter text on the serial monitor and this will display as a
            // Speed for the display is controlled by a pot on SPEED_IN analog in.
            #include <MD_MAX72xx.h>                     // multipurpose library for MAX72xx diaplay driver  https://parola.codeplex.com/
            #include <MySensor.h>                       // Mysensor network
            #include <SPI.h>
            #include <Time.h>                           //http://playground.arduino.cc/Code/Time
            #define PRINT_CALLBACK  0
            
            // Macro to simplify serial print
            #define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
            #define  PRINTS(x) Serial.print(F(x))
            #define PRINTD(x) Serial.println(x, DEC)
            
            // Define the number of devices we have in the chain and the hardware interface
            // need to be adapted to your setup
            const int MAX_DEVICES = 8 ;                 // number of 8x8 displays
            const int CLK_PIN = 7 ;                     // SPI like clock
            const int DATA_PIN = 8 ;                    // SPI like data
            const int CS_PIN = 6 ;                      // SPI like select
            
            
            // Parola is able to use SPI hardware interface, not testted in combination with MySensors
            // MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
            // now use Arbitrary pins
            MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); // instantiate one display chain
            
            
            const int SCROLL_DELAY = 20 ;               // in milliseconds
            
            
            const int CHAR_SPACING = 1 ;                // pixels between characters
            
            int statetus_tame = 1;
            char sdate[11];
            char stime[9];
            // MySensors constants & variables
            //const byte nodeId = 51 ;                    // MySensors fixed node id
            const byte messageCHILD = 8 ;               // Text from ControllerLCD
            const byte brightnessChild = 9 ;            // Brightness of display
            const byte alarmChild = 10 ;                // Display Alarm text (overrides normal text)
            boolean timeReceived = false ;              // Flag to indicate time received
            // Display constants & variables
            byte textBrightness = 1 ;                   // brightness of display (between 0 - MAX_INTENSITY (0xF)
            byte textOnOff = true ;                     // textOnOff = ! shutdown
            boolean textAlarm = false ;                 // Alarm (switch S_BINARY)
            // Global message buffers shared by MySensors and Scrolling functions
            const int BUF_SIZE = 25 ;                   // max payload for MySensors(NRF24l01)
            char curMessage[BUF_SIZE];                  // current displayed message
            char newMessage[BUF_SIZE];                  // next message to be displayed if available
            bool newMessageAvailable = false ;          // new message available flag
            uint16_t    scrollDelay;                    // in milliseconds
            
            // *** Definition and initialisation
            // define the MySensor network (1.5)
            // Initialize messages for sensor network
            MyMessage textMsg(messageCHILD, V_TEXT);    // message for Sending Text to Controller
            
            
            /* MD_MAX72XX functions: can be found in the documentation for the library,
               no need to customtize callback & scroll routines (unless you want to...)
            */
            uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
            // Callback function for data that is required for scrolling into the display
            {
              static char       *p = curMessage;
              static uint8_t    state = 0;
              static uint8_t    curLen, showLen;
              static uint8_t    cBuf[8];
              uint8_t colData;
            
              // finite state machine to control what we do on the callback
              switch (state)
              {
                case 0: // Load the next character from the font table
                  showLen = mx.getChar(*p++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf);
                  curLen = 0;
                  state++;
            
                  // if we reached end of message, reset the message pointer
                  if (*p == '\0')
                  {
                    p = curMessage;         // reset the pointer to start of message
                    if (newMessageAvailable)    // there is a new message waiting
                    {
                      strcpy(curMessage, newMessage);   // copy it in
                      newMessageAvailable = false;
                    }
                  }
                // !! deliberately fall through to next state to start displaying
            
                case 1: // display the next part of the character
                  colData = cBuf[curLen++];
                  if (curLen == showLen)                // end of character insert interchar space
                  {
                    showLen = CHAR_SPACING;
                    curLen = 0;
                    state = 2;
                  }
                  break;
            
                case 2: // display inter-character spacing (blank column)
                  colData = 0;
                  curLen++;
                  if (curLen == showLen)
                    state = 0;
                  break;
            
                default:
                  state = 0;
              }
            
              return (colData);
            }
            
            void printText(uint8_t modStart, uint8_t modEnd, char *pMsg)
            // Print the text string to the LED matrix modules specified.
            // Message area is padded with blank columns after printing.
            {
              uint8_t   state = 0;
              uint8_t    curLen;
              uint16_t  showLen;
              uint8_t   cBuf[8];
              int16_t   col = ((modEnd + 1) * COL_SIZE) - 1;
              mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
            
              do     // finite state machine to print the characters in the space available
              {
                switch (state)
                {
                  case 0: // Load the next character from the font table
                    // if we reached end of message, reset the message pointer
                    if (*pMsg == '\0')
                    {
                      showLen = col - (modEnd * COL_SIZE);  // padding characters
                      state = 2;
                      break;
                    }
                    // retrieve the next character form the font file
                    showLen = mx.getChar(*pMsg++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf);
                    curLen = 0;
                    state++;
                  // !! deliberately fall through to next state to start displaying
            
                  case 1: // display the next part of the character
                    mx.setColumn(col--, cBuf[curLen++]);
                    // done with font character, now display the space between chars
                    if (curLen == showLen)
                    {
                      showLen = CHAR_SPACING;
                      state = 2;
                    }
                    break;
            
                  case 2: // initialize state for displaying empty columns
                    curLen = 0;
                    state++;
                  // fall through
            
                  case 3: // display inter-character spacing or end of message padding (blank columns)
                    mx.setColumn(col--, 0);
                    curLen++;
                    if (curLen == showLen)
                      state = 0;
                    break;
            
                  default:
                    col = -1;   // this definitely ends the do loop
                }
              } while (col >= (modStart * COL_SIZE));
              mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
            
            }
            
            
            void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col) {
              // Callback function for data that is being scrolled off the display
            #if PRINT_CALLBACK
              Serial.print("\n cb ");
              Serial.print(dev);
              Serial.print(' ');
              Serial.print(t);
              Serial.print(' ');
              Serial.println(col);
            #endif
            }
            
            // non-blocking text display to be used in loop (call frequently)
            void scrollText(void) {
              static uint32_t prevTime = 0;
              if (millis() - prevTime >= scrollDelay) {               // Is it time to scroll the text?
                mx.transform(MD_MAX72XX::TSL);                      // scroll along - the callback will load all the data
                prevTime = millis();                                // starting point for next time
              }
            }
            
            // sets the scroll delay (read from potentiometer if enabled)
            uint16_t getScrollDelay(void) {
              return (SCROLL_DELAY);
            }
            
            void setup() {
              // set up the display first
              mx.begin();                                             // initialize display chain
              mx.setShiftDataInCallback(scrollDataSource);            // define function to get the scrolldata (returned as int8)
              //mx.setShiftDataOutCallback(scrollDataSink);           // not used
              mx.control(MD_MAX72XX::INTENSITY, 0x01);
              scrollDelay = SCROLL_DELAY;
            
            
              strcpy(curMessage, "I \x03 MySensors ");                // first message on display
              newMessage[0] = '\0';                                   // new message initialized to empty
              // Setup MySensors
              //Serial in Sensor network = 115200
              //Send the sensor node sketch version information to the gateway
            
            }
            
            void presentation() {
            
              sendSketchInfo("AWI Scroll MAX 51", "1.1");
              present(messageCHILD, S_INFO, "Text line Scroll");   // new S_type 20150905 (not know by domoticz)
              present(alarmChild, S_BINARY, "Alarm display");      // to display alarm text
              present(brightnessChild, S_DIMMER, "Text brightness"); // new S_type 20150905 (not know by domoticz)
              //send(textMsg.set("-"));                            // initialize the V_TEXT at controller for sensor to none (trick for Domoticz)
              request(messageCHILD, V_TEXT, 0);                    // request value from controller
              // Initializations
              requestTime();                            // get the time from controller (handled by receiveTime)
            }
            
            
            // loop only uses non-blocking functions
            void loop() {
              static unsigned long lastUpdate ;                       // Static hold the last update time
              static unsigned long lastUpdate2 ;                       // Static hold the last update time
              unsigned long now = millis();
              scrollDelay = getScrollDelay();                         // update scroll delay from potentiometer
              readSerial();
              // Check for new conditions & ask for new information from controller every 10 seconds
              if (now - lastUpdate > 30000 && statetus_tame == 0) {
                statetus_tame = 0;
                sprintf(sdate, "%02d-%02d-%d", day(), month(), year());
                printText(0, MAX_DEVICES - 1, sdate);
                lastUpdate = now;
              }
              if (textAlarm) {                                    // if alarmstatus: override all text and set max intensity
                //strcpy(curMessage, "   ALARM   ");
                mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY);   // set current brightness
                mx.control(MD_MAX72XX::SHUTDOWN, false) ;
              } else {                                            // standard (non Alarm actions)
               /* 
                  mx.control(MD_MAX72XX::INTENSITY, textBrightness);  // set current brightness
                  mx.control(MD_MAX72XX::SHUTDOWN, textOnOff) ;
                  request(messageCHILD, V_TEXT, 0);                // request new value from controller
                */
              }
              if (textAlarm) {
                scrollText();
              } else {
                //sprintf(stime, "%02d:%02d:%02d", hour(), minute(), second());
                if (statetus_tame == 1) {
                  sprintf(stime, "%02d:%02d:%02d", hour(), minute(), second());
                  printText(0, MAX_DEVICES - 3, stime);
                  mx.setShiftDataOutCallback(scrollDataSink);
                }
                mx.control(MD_MAX72XX::INTENSITY, textBrightness);   // set current brightness
              }
              if (now - lastUpdate2 > 32000) {
                statetus_tame = 1;
                mx.clear();
                lastUpdate2 = now;
              }
            if (now - lastUpdate >33000 ){
              requestTime();
              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 receive(const MyMessage &message) {
              Serial.print("Message: "); Serial.print(message.sensor); Serial.print(", Message: "); Serial.println(message.getString());
              if (message.sensor == messageCHILD) {
                if (message.type == V_TEXT) {                   // Text content
                  strcpy(newMessage, message.getString());        // copy it in
                  newMessageAvailable = true ;
                }
              } else if (message.sensor == alarmChild) {
                if (message.type == V_STATUS) {                 // True/ false content
                  textAlarm = message.getBool() ? true : false ; // set alarmflag
                  Serial.print("TextAlarm: ");
                  Serial.println(textAlarm);
                }
              } else if (message.sensor == brightnessChild) {
                if (message.type == V_PERCENTAGE) {             // Level 0..100  content
                  textBrightness = map(message.getInt(), 0, 100, 0, MAX_INTENSITY ) ; // map to brightnesslevel
                  Serial.print("TextBrightness: ");
                  Serial.println(textBrightness);
                } else if (message.type == V_STATUS) {          // Display on/off
                  textOnOff = message.getBool() ? false : true ;  // set shutdown/ !on/off
                  Serial.print("Text on/off: ");
                  Serial.println(textOnOff);
                }
              }
            }
            
            
            // Testing purposes: input routine character buffer. Reads serial characters in buffer newMessage.
            // sets flag newMessageAvailable to true if completed
            void readSerial(void)
            {
              static uint8_t    putIndex = 0;
            
              while (Serial.available())
              {
                newMessage[putIndex] = (char)Serial.read();
                if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE - 3)) // end of message character or full buffer
                {
                  // put in a message separator and end the string
                  newMessage[putIndex++] = ' ';
                  newMessage[putIndex] = '\0';
                  // restart the index for next filling spree and flag we have a message waiting
                  putIndex = 0;
                  newMessageAvailable = true;
                }
                else
                  // Just save the next char in next location
                  newMessage[putIndex++];
              }
            }
            
            
            korttomaK 1 Reply Last reply
            1
            • A artur

              @korttoma

              Here are found the blank, you need to check how it works

              /*
                PROJECT: MySensors / Scrolling Text display
                PROGRAMMER: AWI
                DATE: september 12, 2015/ last update: september 12, 2015
                FILE: AWI_scroll_MAX.ino
                LICENSE: Public domain
              
                Hardware: tbd ..Ceech - ATmega328p board w/ NRF24l01
                  and MySensors 1.5 ()
              
                Special:
                  Need to use MySensors development edition
              
                SUMMARY:
                  3 S_xx devices for scrolling text
                  - Displays a scrolling text from a "V_TEXT" variable
                  - additional dimmer sensor for controlling display brightness
                  - 'Alarm' switch. If "On", overrides the text display to display ALARM message
                  - You can also input messages from the Serial monitor (testing)
                  Uses excellent MD_MAX72XX library
                Remarks:
                  Fixed node-id
              */
              // Enable debug prints to serial monitor
              #define MY_DEBUG
              
              // Enable and select radio type attached
              #define MY_RADIO_NRF24
              //#define MY_RADIO_RFM69
              
              #define  DEBUG 0   // Enable or disable (default) debugging output
              
              // Use the MD_MAX72XX library to scroll text on the display with the use of the callback function
              // to control what is scrolled on the display text.
              // You need to set the used display in the library MD_MAX72XX.h
              // User can enter text on the serial monitor and this will display as a
              // Speed for the display is controlled by a pot on SPEED_IN analog in.
              #include <MD_MAX72xx.h>                     // multipurpose library for MAX72xx diaplay driver  https://parola.codeplex.com/
              #include <MySensor.h>                       // Mysensor network
              #include <SPI.h>
              #include <Time.h>                           //http://playground.arduino.cc/Code/Time
              #define PRINT_CALLBACK  0
              
              // Macro to simplify serial print
              #define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }
              #define  PRINTS(x) Serial.print(F(x))
              #define PRINTD(x) Serial.println(x, DEC)
              
              // Define the number of devices we have in the chain and the hardware interface
              // need to be adapted to your setup
              const int MAX_DEVICES = 8 ;                 // number of 8x8 displays
              const int CLK_PIN = 7 ;                     // SPI like clock
              const int DATA_PIN = 8 ;                    // SPI like data
              const int CS_PIN = 6 ;                      // SPI like select
              
              
              // Parola is able to use SPI hardware interface, not testted in combination with MySensors
              // MD_MAX72XX mx = MD_MAX72XX(CS_PIN, MAX_DEVICES);
              // now use Arbitrary pins
              MD_MAX72XX mx = MD_MAX72XX(DATA_PIN, CLK_PIN, CS_PIN, MAX_DEVICES); // instantiate one display chain
              
              
              const int SCROLL_DELAY = 20 ;               // in milliseconds
              
              
              const int CHAR_SPACING = 1 ;                // pixels between characters
              
              int statetus_tame = 1;
              char sdate[11];
              char stime[9];
              // MySensors constants & variables
              //const byte nodeId = 51 ;                    // MySensors fixed node id
              const byte messageCHILD = 8 ;               // Text from ControllerLCD
              const byte brightnessChild = 9 ;            // Brightness of display
              const byte alarmChild = 10 ;                // Display Alarm text (overrides normal text)
              boolean timeReceived = false ;              // Flag to indicate time received
              // Display constants & variables
              byte textBrightness = 1 ;                   // brightness of display (between 0 - MAX_INTENSITY (0xF)
              byte textOnOff = true ;                     // textOnOff = ! shutdown
              boolean textAlarm = false ;                 // Alarm (switch S_BINARY)
              // Global message buffers shared by MySensors and Scrolling functions
              const int BUF_SIZE = 25 ;                   // max payload for MySensors(NRF24l01)
              char curMessage[BUF_SIZE];                  // current displayed message
              char newMessage[BUF_SIZE];                  // next message to be displayed if available
              bool newMessageAvailable = false ;          // new message available flag
              uint16_t    scrollDelay;                    // in milliseconds
              
              // *** Definition and initialisation
              // define the MySensor network (1.5)
              // Initialize messages for sensor network
              MyMessage textMsg(messageCHILD, V_TEXT);    // message for Sending Text to Controller
              
              
              /* MD_MAX72XX functions: can be found in the documentation for the library,
                 no need to customtize callback & scroll routines (unless you want to...)
              */
              uint8_t scrollDataSource(uint8_t dev, MD_MAX72XX::transformType_t t)
              // Callback function for data that is required for scrolling into the display
              {
                static char       *p = curMessage;
                static uint8_t    state = 0;
                static uint8_t    curLen, showLen;
                static uint8_t    cBuf[8];
                uint8_t colData;
              
                // finite state machine to control what we do on the callback
                switch (state)
                {
                  case 0: // Load the next character from the font table
                    showLen = mx.getChar(*p++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf);
                    curLen = 0;
                    state++;
              
                    // if we reached end of message, reset the message pointer
                    if (*p == '\0')
                    {
                      p = curMessage;         // reset the pointer to start of message
                      if (newMessageAvailable)    // there is a new message waiting
                      {
                        strcpy(curMessage, newMessage);   // copy it in
                        newMessageAvailable = false;
                      }
                    }
                  // !! deliberately fall through to next state to start displaying
              
                  case 1: // display the next part of the character
                    colData = cBuf[curLen++];
                    if (curLen == showLen)                // end of character insert interchar space
                    {
                      showLen = CHAR_SPACING;
                      curLen = 0;
                      state = 2;
                    }
                    break;
              
                  case 2: // display inter-character spacing (blank column)
                    colData = 0;
                    curLen++;
                    if (curLen == showLen)
                      state = 0;
                    break;
              
                  default:
                    state = 0;
                }
              
                return (colData);
              }
              
              void printText(uint8_t modStart, uint8_t modEnd, char *pMsg)
              // Print the text string to the LED matrix modules specified.
              // Message area is padded with blank columns after printing.
              {
                uint8_t   state = 0;
                uint8_t    curLen;
                uint16_t  showLen;
                uint8_t   cBuf[8];
                int16_t   col = ((modEnd + 1) * COL_SIZE) - 1;
                mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);
              
                do     // finite state machine to print the characters in the space available
                {
                  switch (state)
                  {
                    case 0: // Load the next character from the font table
                      // if we reached end of message, reset the message pointer
                      if (*pMsg == '\0')
                      {
                        showLen = col - (modEnd * COL_SIZE);  // padding characters
                        state = 2;
                        break;
                      }
                      // retrieve the next character form the font file
                      showLen = mx.getChar(*pMsg++, sizeof(cBuf) / sizeof(cBuf[0]), cBuf);
                      curLen = 0;
                      state++;
                    // !! deliberately fall through to next state to start displaying
              
                    case 1: // display the next part of the character
                      mx.setColumn(col--, cBuf[curLen++]);
                      // done with font character, now display the space between chars
                      if (curLen == showLen)
                      {
                        showLen = CHAR_SPACING;
                        state = 2;
                      }
                      break;
              
                    case 2: // initialize state for displaying empty columns
                      curLen = 0;
                      state++;
                    // fall through
              
                    case 3: // display inter-character spacing or end of message padding (blank columns)
                      mx.setColumn(col--, 0);
                      curLen++;
                      if (curLen == showLen)
                        state = 0;
                      break;
              
                    default:
                      col = -1;   // this definitely ends the do loop
                  }
                } while (col >= (modStart * COL_SIZE));
                mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
              
              }
              
              
              void scrollDataSink(uint8_t dev, MD_MAX72XX::transformType_t t, uint8_t col) {
                // Callback function for data that is being scrolled off the display
              #if PRINT_CALLBACK
                Serial.print("\n cb ");
                Serial.print(dev);
                Serial.print(' ');
                Serial.print(t);
                Serial.print(' ');
                Serial.println(col);
              #endif
              }
              
              // non-blocking text display to be used in loop (call frequently)
              void scrollText(void) {
                static uint32_t prevTime = 0;
                if (millis() - prevTime >= scrollDelay) {               // Is it time to scroll the text?
                  mx.transform(MD_MAX72XX::TSL);                      // scroll along - the callback will load all the data
                  prevTime = millis();                                // starting point for next time
                }
              }
              
              // sets the scroll delay (read from potentiometer if enabled)
              uint16_t getScrollDelay(void) {
                return (SCROLL_DELAY);
              }
              
              void setup() {
                // set up the display first
                mx.begin();                                             // initialize display chain
                mx.setShiftDataInCallback(scrollDataSource);            // define function to get the scrolldata (returned as int8)
                //mx.setShiftDataOutCallback(scrollDataSink);           // not used
                mx.control(MD_MAX72XX::INTENSITY, 0x01);
                scrollDelay = SCROLL_DELAY;
              
              
                strcpy(curMessage, "I \x03 MySensors ");                // first message on display
                newMessage[0] = '\0';                                   // new message initialized to empty
                // Setup MySensors
                //Serial in Sensor network = 115200
                //Send the sensor node sketch version information to the gateway
              
              }
              
              void presentation() {
              
                sendSketchInfo("AWI Scroll MAX 51", "1.1");
                present(messageCHILD, S_INFO, "Text line Scroll");   // new S_type 20150905 (not know by domoticz)
                present(alarmChild, S_BINARY, "Alarm display");      // to display alarm text
                present(brightnessChild, S_DIMMER, "Text brightness"); // new S_type 20150905 (not know by domoticz)
                //send(textMsg.set("-"));                            // initialize the V_TEXT at controller for sensor to none (trick for Domoticz)
                request(messageCHILD, V_TEXT, 0);                    // request value from controller
                // Initializations
                requestTime();                            // get the time from controller (handled by receiveTime)
              }
              
              
              // loop only uses non-blocking functions
              void loop() {
                static unsigned long lastUpdate ;                       // Static hold the last update time
                static unsigned long lastUpdate2 ;                       // Static hold the last update time
                unsigned long now = millis();
                scrollDelay = getScrollDelay();                         // update scroll delay from potentiometer
                readSerial();
                // Check for new conditions & ask for new information from controller every 10 seconds
                if (now - lastUpdate > 30000 && statetus_tame == 0) {
                  statetus_tame = 0;
                  sprintf(sdate, "%02d-%02d-%d", day(), month(), year());
                  printText(0, MAX_DEVICES - 1, sdate);
                  lastUpdate = now;
                }
                if (textAlarm) {                                    // if alarmstatus: override all text and set max intensity
                  //strcpy(curMessage, "   ALARM   ");
                  mx.control(MD_MAX72XX::INTENSITY, MAX_INTENSITY);   // set current brightness
                  mx.control(MD_MAX72XX::SHUTDOWN, false) ;
                } else {                                            // standard (non Alarm actions)
                 /* 
                    mx.control(MD_MAX72XX::INTENSITY, textBrightness);  // set current brightness
                    mx.control(MD_MAX72XX::SHUTDOWN, textOnOff) ;
                    request(messageCHILD, V_TEXT, 0);                // request new value from controller
                  */
                }
                if (textAlarm) {
                  scrollText();
                } else {
                  //sprintf(stime, "%02d:%02d:%02d", hour(), minute(), second());
                  if (statetus_tame == 1) {
                    sprintf(stime, "%02d:%02d:%02d", hour(), minute(), second());
                    printText(0, MAX_DEVICES - 3, stime);
                    mx.setShiftDataOutCallback(scrollDataSink);
                  }
                  mx.control(MD_MAX72XX::INTENSITY, textBrightness);   // set current brightness
                }
                if (now - lastUpdate2 > 32000) {
                  statetus_tame = 1;
                  mx.clear();
                  lastUpdate2 = now;
                }
              if (now - lastUpdate >33000 ){
                requestTime();
                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 receive(const MyMessage &message) {
                Serial.print("Message: "); Serial.print(message.sensor); Serial.print(", Message: "); Serial.println(message.getString());
                if (message.sensor == messageCHILD) {
                  if (message.type == V_TEXT) {                   // Text content
                    strcpy(newMessage, message.getString());        // copy it in
                    newMessageAvailable = true ;
                  }
                } else if (message.sensor == alarmChild) {
                  if (message.type == V_STATUS) {                 // True/ false content
                    textAlarm = message.getBool() ? true : false ; // set alarmflag
                    Serial.print("TextAlarm: ");
                    Serial.println(textAlarm);
                  }
                } else if (message.sensor == brightnessChild) {
                  if (message.type == V_PERCENTAGE) {             // Level 0..100  content
                    textBrightness = map(message.getInt(), 0, 100, 0, MAX_INTENSITY ) ; // map to brightnesslevel
                    Serial.print("TextBrightness: ");
                    Serial.println(textBrightness);
                  } else if (message.type == V_STATUS) {          // Display on/off
                    textOnOff = message.getBool() ? false : true ;  // set shutdown/ !on/off
                    Serial.print("Text on/off: ");
                    Serial.println(textOnOff);
                  }
                }
              }
              
              
              // Testing purposes: input routine character buffer. Reads serial characters in buffer newMessage.
              // sets flag newMessageAvailable to true if completed
              void readSerial(void)
              {
                static uint8_t    putIndex = 0;
              
                while (Serial.available())
                {
                  newMessage[putIndex] = (char)Serial.read();
                  if ((newMessage[putIndex] == '\n') || (putIndex >= BUF_SIZE - 3)) // end of message character or full buffer
                  {
                    // put in a message separator and end the string
                    newMessage[putIndex++] = ' ';
                    newMessage[putIndex] = '\0';
                    // restart the index for next filling spree and flag we have a message waiting
                    putIndex = 0;
                    newMessageAvailable = true;
                  }
                  else
                    // Just save the next char in next location
                    newMessage[putIndex++];
                }
              }
              
              
              korttomaK Offline
              korttomaK Offline
              korttoma
              Hero Member
              wrote on last edited by korttoma
              #47

              @artur thanks for your example. I managed to make it show the time. Now I just need to figure out how to make it show the text also.

              • Tomas
              1 Reply Last reply
              0
              • S Offline
                S Offline
                shabba
                wrote on last edited by
                #48

                Sorry for hijack. I am trying to get domoticz to show text from a node but am not able to.

                present(2, S_INFO, "Gate Open Reason");
                [..]
                MyMessage msg2(2,V_TEXT);
                [..]
                String reason = "blah";
                send(msg2.set(reason));

                But domoticz only shows a 1. Probably missing something obvious?

                AWIA 1 Reply Last reply
                0
                • S shabba

                  Sorry for hijack. I am trying to get domoticz to show text from a node but am not able to.

                  present(2, S_INFO, "Gate Open Reason");
                  [..]
                  MyMessage msg2(2,V_TEXT);
                  [..]
                  String reason = "blah";
                  send(msg2.set(reason));

                  But domoticz only shows a 1. Probably missing something obvious?

                  AWIA Offline
                  AWIA Offline
                  AWI
                  Hero Member
                  wrote on last edited by
                  #49

                  @shabba Try without using "String" type use "char[x]" instead. In general you should try to avoid using this type in real time environments. send(msg2.set("Blah")); should do the trick in first instance.

                  S 1 Reply Last reply
                  0
                  • AWIA AWI

                    @shabba Try without using "String" type use "char[x]" instead. In general you should try to avoid using this type in real time environments. send(msg2.set("Blah")); should do the trick in first instance.

                    S Offline
                    S Offline
                    shabba
                    wrote on last edited by
                    #50

                    @AWI Derp! Looking at the headers that looks right! Will try a little later and report. Thanks!

                    1 Reply Last reply
                    0
                    • S Offline
                      S Offline
                      shabba
                      wrote on last edited by
                      #51

                      I just did send(msg2.set(reason.c_str())); and it worked. Thanks @AWI

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      30

                      Online

                      11.7k

                      Users

                      11.2k

                      Topics

                      113.1k

                      Posts


                      Copyright 2025 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • MySensors
                      • OpenHardware.io
                      • Categories
                      • Recent
                      • Tags
                      • Popular