Weather and Forecast Display for Swedish FHEM users


  • Hardware Contributor

    My need for a indoor and outdoor temperature and weather display was a part of my try-out of Fhem as a MySensors Controller. It turned out surprisingly well. A bit of newbie struggling with German, Perl and regExp I admit, but in the end it turned out to be more simple than that. It was actually harder to make it display the weather forecast conditions in Swedish, which was finally solved by using the weather provider condition code, progmem and custum created lcd characters.

    I hope bits and pieces can be useful even if you don't want the exact same application.
    bild1.jpg

    The project was based on the MySensors display exemple and BulldogLowell's weather station project.
    Where some of my modifications to that are:

    • Removed scene controller button and internal sensor functionality.
    • Changed date and time format
    • Fewer slides and less static information per slide.
    • Some more info from controller (other sensors).
    • Weather conditions in Swedish

    Controller (FHEM) runs on a RPiB+ and MySensors gateway is Ethernet(W5100). Perhaps it could be necessary to add timers to the controllers "set" transmission code with a faster one. I haven't seen any issues this far (a week).

    The wiring is just the basic for radio and display.

    And I used this box and this display and i2c-interface.

    Slide 1 presents date and time and update-status if time or weather not has been updated in a while (some hours).
    Slide 2 Indoor and outdoor temperature and humidity. (preferably from other MYS-nodes, but for this particular project I used the weather service providers data for outdoor temp only because my mys-network hasn't any "outdoor access")
    Slide 3 Today's forecast and High temp and Low temp.
    Slide 4 Tomorrow's forecast, high temp and low temp.

    bild2.jpg
    bild3.jpg
    bild4.jpg
    bild5.jpg

    fhem.cfg -extract
    (Creation of weather service and other MySensor devices should be straight forward. I'll try to help and share more if there are questions.)

    define MYSENSOR_112 MYSENSORS_DEVICE 112
    attr MYSENSOR_112 IODev mysEthGateway1
    attr MYSENSOR_112 mapReading_button_off3 3 button_off
    attr MYSENSOR_112 mapReading_button_on3 3 button_on
    attr MYSENSOR_112 mapReading_conditions 3 value5
    attr MYSENSOR_112 mapReading_forecast 4 value3
    attr MYSENSOR_112 mapReading_inHumid 4 value2
    attr MYSENSOR_112 mapReading_inTemp 4 value1
    attr MYSENSOR_112 mapReading_outHumid 3 value2
    attr MYSENSOR_112 mapReading_outTemp 3 value1
    attr MYSENSOR_112 mapReading_switch4 4 switch
    attr MYSENSOR_112 mapReading_todayHigh 3 value4
    attr MYSENSOR_112 mapReading_todayLow 3 value3
    attr MYSENSOR_112 mapReading_tomorrowHigh 4 value4
    attr MYSENSOR_112 mapReading_tomorrowLow 4 value5
    attr MYSENSOR_112 mode node
    attr MYSENSOR_112 room Hall
    attr MYSENSOR_112 setReading_conditions 1
    attr MYSENSOR_112 setReading_forecast 1
    attr MYSENSOR_112 setReading_inHumid 1
    attr MYSENSOR_112 setReading_inTemp 1
    attr MYSENSOR_112 setReading_outHumid 1
    attr MYSENSOR_112 setReading_outTemp 1
    attr MYSENSOR_112 setReading_switch4 on,off
    attr MYSENSOR_112 setReading_todayHigh 1
    attr MYSENSOR_112 setReading_todayLow 1
    attr MYSENSOR_112 setReading_tomorrowHigh 1
    attr MYSENSOR_112 setReading_tomorrowLow 1
    attr MYSENSOR_112 stateFormat switch4
    attr MYSENSOR_112 verbose 3
    attr MYSENSOR_112 version 1.4.1
    
    define myWeather2disp_ntfy notify myWeather {\
      my $a=ReadingsVal("myWeather","humidity",0);;;;\
      fhem("set MYSENSOR_112 outHumid ".$a);;;;\
      $a=ReadingsVal("myWeather","temp_c",0);;;;\
      fhem("set MYSENSOR_112 outTemp ".$a);;;;\
      $a=ReadingsVal("myWeather","fc1_high_c",0);;;;\
      fhem("set MYSENSOR_112 todayHigh ".$a);;;;\
      $a=ReadingsVal("myWeather","fc1_low_c",0);;;;\
      fhem("set MYSENSOR_112 todayLow ".$a);;;;\
      $a=ReadingsVal("myWeather","fc2_high_c",0);;;;\
      fhem("set MYSENSOR_112 tomorrowHigh ".$a);;;;\
      $a=ReadingsVal("myWeather","fc2_low_c",0);;;;\
      fhem("set MYSENSOR_112 tomorrowLow ".$a);;;;\
      $a=ReadingsVal("myWeather","fc1_code",0);;;;\
      fhem("set MYSENSOR_112 conditions ".$a);;;;\
      $a=ReadingsVal("myWeather","fc2_code",0);;;;\
      fhem("set MYSENSOR_112 forecast ".$a)\
    }
    attr myWeather2disp_ntfy room Macro,Hall
    
    define myIndoorTemp2disp_ntfy notify MYSENSOR_105 {\
      my $a=ReadingsVal("MYSENSOR_105","temperature1",0);;;;\
      $a=int($a+0.5);;;;\
      fhem("set MYSENSOR_112 inTemp ".$a);;;;\
      $a=ReadingsVal("MYSENSOR_105","humidity",0);;;;\
      $a=int($a+0.5);;;;\
      fhem("set MYSENSOR_112 inHumid ".$a)\
    }
    attr myIndoorTemp2disp_ntfy room Hall,Macro
    

    Sensor (Display) Node Code
    (v2.5 presented below, original 2.3 is here.)

    /* 
    EgWeatherDisplay2.5
    Weather Display for FHEM with Swedish conditions
    By m26872, 20150826
    changes from 2.4 to 2.5
    - Automatic DST time for the next 4 years (controller still sync with UTC)
    - Now use the gw.wait()
    - Cleaned displays from some static info
    - Updated child-ids, sensor and variable definitions to to aline with MySensors 1.5 and to avoid unwanted autocreations by fhem.
    changes from 2.3 to 2.4
    - New (correct) translations for some conditions
    - Removed two unused "scene button" declarations.
    */
    
    #define STATES 4
    #define CLOCK_SYNC_INTERVAL 3600000UL  // 1 hour
    #define DISPLAY_INTERVAL 3500UL  // 3,5s
    #define FIVE_HOURS 18000000UL
    #define THREE_HOURS 10800000UL
    #define ONE_MIN 60000UL
    #define DST_YEARS 5
    #define Y2015_DST_ON 1427594400UL  // 2015-03-29 02:00
    #define Y2015_DST_OFF 1445738400UL  // 2015-10-25 02:00     1445742000UL  // 2015-10-25 03:00
    #define Y2016_DST_ON 1459044000UL  // 2016-03-27 02:00
    #define Y2016_DST_OFF 1477792800UL  // 2016-10-30 02:00
    #define Y2017_DST_ON 1490493600UL  // 2017-03-26 02:00
    #define Y2017_DST_OFF 1509242400UL  // 2017-10-29 02:00
    #define Y2018_DST_ON 1521943200UL  // 2018-03-25 02:00
    #define Y2018_DST_OFF 1540692000UL  // 2018-10-28 02:00
    #define Y2019_DST_ON 1553997600UL  // 2019-03-31 02:00
    #define Y2019_DST_OFF 1572141600UL  // 2019-10-27 02:00
    
    #define DEBUG
    
    #ifdef DEBUG
    #define DEBUG_SERIAL(x) Serial.begin(x)
    #define DEBUG_PRINT(x) Serial.print(x)
    #define DEBUG_PRINTLN(x) Serial.println(x)
    #else
    #define DEBUG_SERIAL(x)
    #define DEBUG_PRINT(x) 
    #define DEBUG_PRINTLN(x) 
    #endif
    
    #include <avr/pgmspace.h>
    #include <Wire.h>
    #include <Time.h>
    #include <SPI.h>
    #include <MySensor.h>
    #include <LiquidCrystal_I2C.h>
    
    #define NODE_ID 112
    #define CHILD_ID_3 3
    #define CHILD_ID_4 4
    
    LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address (Enl: https://arduino-info.wikispaces.com/LCD-Blue-I2C)
    
    void (*lcdDisplay[STATES])();
    
    byte state = STATES-1;
    byte timeCounter = 0;
    unsigned long lastTime;
    unsigned long lastClockSet;
    unsigned long lastClockReceived = 0UL;
    unsigned long lastWeatherUpdate = 0UL;
    int indoorTemp = -99;
    int indoorHumidity = -99;
    int outdoorTemp = -99;
    int outdoorHumidity = -99;
    int todayHigh = -99; 
    int todayLow = -99;
    int tomorrowHigh = -99; 
    int tomorrowLow = -99;
    int todayConditionCode = -99;
    int tomorrowConditionCode = -99;
    String todayCondition = "Not yet Reported";
    String tomorrowCondition = "Not yet Reported";
    unsigned long dstTable[DST_YEARS][2] = {{Y2015_DST_ON,Y2015_DST_OFF},{Y2016_DST_ON,Y2016_DST_OFF},{Y2017_DST_ON,Y2017_DST_OFF},{Y2018_DST_ON,Y2018_DST_OFF},{Y2019_DST_ON,Y2019_DST_OFF}}; 
    
    // MySensor related
    MySensor gw;
    
    MyMessage msgVAR1(CHILD_ID_3, V_VAR1);// outdoor temperature
    MyMessage msgVAR2(CHILD_ID_3, V_VAR2);// outdoor humidity
    MyMessage msgVAR3(CHILD_ID_3, V_VAR3);// today's low
    MyMessage msgVAR4(CHILD_ID_3, V_VAR4);// today's high
    MyMessage msgVAR5(CHILD_ID_3, V_VAR5);// conditions
    
    MyMessage msgBackLight(CHILD_ID_4, V_STATUS);
    MyMessage msgLVAR1(CHILD_ID_4, V_VAR1); // indoor temperature
    MyMessage msgLVAR2(CHILD_ID_4, V_VAR2); // indoor humidity
    MyMessage msgLVAR3(CHILD_ID_4, V_VAR3); // forecast for tomorrow 
    
    // Swedish weather condition translations stored to flash. Special characters (å,ä,ö,Å,Ä,Ö) substituted with resp. LCD custom made character (01-06).
    	const char cs0[] PROGMEM = "Tornado";   // tornado
    	const char cs1[] PROGMEM = "Tropisk storm";   // tropical storm
    	const char cs2[] PROGMEM = "Orkan";    // hurricane
    	const char cs3[] PROGMEM = "Kraftig \01ska";    // severe thunderstorms
    	const char cs4[] PROGMEM = "\04ska";    // thunderstorms
    	const char cs5[] PROGMEM = "Sn\03blandat regn";    // mixed rain and snow
    	const char cs6[] PROGMEM = "Regn o bl\03tsn\03";    // mixed rain and sleet
    	const char cs7[] PROGMEM = "Sn\03 och bl\03tsn\03";    // mixed snow and sleet
    	const char cs8[] PROGMEM = "Underkylt dugg";    // freezing drizzle
    	const char cs9[] PROGMEM = "Duggregn";    // drizzle
    	const char cs10[] PROGMEM = "Underkylt regn";    // freezing rain
    	const char cs11[] PROGMEM = "Skurar";    // showers
    	const char cs12[] PROGMEM = "Skurar";    // showers
    	const char cs13[] PROGMEM = "Sn\03 o vindbyar";    // snow flurries
    	const char cs14[] PROGMEM = "L\02tta sn\03byar";    // light snow showers
    	const char cs15[] PROGMEM = "Sn\03 o bl\01st";    // blowing snow
    	const char cs16[] PROGMEM = "Sn\03";    // snow
    	const char cs17[] PROGMEM = "Hagel";    // hail
    	const char cs18[] PROGMEM = "Bl\03tsn\03";    // sleet
    	const char cs19[] PROGMEM = "Damm";    // dust
    	const char cs20[] PROGMEM = "Dimma";    // foggy
    	const char cs21[] PROGMEM = "Disigt";    // haze
    	const char cs22[] PROGMEM = "R\03kigt";    // smoky
    	const char cs23[] PROGMEM = "H\01rd vind";    // blustery
    	const char cs24[] PROGMEM = "Bl\01sigt";    // windy
    	const char cs25[] PROGMEM = "Kallt";    // cold
    	const char cs26[] PROGMEM = "Mulet";    // cloudy
    	const char cs27[] PROGMEM = "\06verv\02g. mulet";    // mostly cloudy (night)
    	const char cs28[] PROGMEM = "\06verv\02g. mulet";    // mostly cloudy (day)
    	const char cs29[] PROGMEM = "V\02xl. molnighet";    // partly cloudy (night)
    	const char cs30[] PROGMEM = "V\02xl. molnighet";    // partly cloudy (day) 
    	const char cs31[] PROGMEM = "Klart";    // clear (night)
    	const char cs32[] PROGMEM = "Soligt";    // sunny
    	const char cs33[] PROGMEM = "\06verv\02g. klart";    // fair (night)
    	const char cs34[] PROGMEM = "\06verv\02g. soligt";    // fair (day)
    	const char cs35[] PROGMEM = "Regn och hagel";    // mixed rain and hail
    	const char cs36[] PROGMEM = "Varmt";    // hot
    	const char cs37[] PROGMEM = "Enstaka \01ska";    // isolated thunderstorms
    	const char cs38[] PROGMEM = "Spridd \01ska";    // scattered thunderstorms
    	const char cs39[] PROGMEM = "Spridd \01ska";    // scattered thunderstorms
    	const char cs40[] PROGMEM = "Spridda skurar";    // scattered showers
    	const char cs41[] PROGMEM = "Krafigt sn\03fall";    // heavy snow
    	const char cs42[] PROGMEM = "Spridda sn\03byar";    // scattered snow showers
    	const char cs43[] PROGMEM = "Krafigt sn\03fall";    // heavy snow
    	const char cs44[] PROGMEM = "V\02xl. molnighet";    // partly cloudy
    	const char cs45[] PROGMEM = "\04skskurar";    // thundershowers
    	const char cs46[] PROGMEM = "Sn\03byar";    // snow showers
    	const char cs47[] PROGMEM = "Enst. \01skskurar";    // isolated thundershowers
    	const char cs48[] PROGMEM = "(not available)";    // (3200) not available
    
    	const char* const condStrTable[] PROGMEM = {cs0,cs1,cs2,cs3,cs4,cs5,cs6,cs7,cs8,cs9,cs10,cs11,cs12,cs13,cs14,cs15,cs16,cs17,cs18,cs19,            cs20,cs21,cs22,cs23,cs24,cs25,cs26,cs27,cs28,cs29,cs30,cs31,cs32,cs33,cs34,cs35,cs36,cs37,cs38,cs39,cs40,cs41,cs42,cs43,cs44,cs45,cs46,cs47,cs48};
    
    	char condString[17];
    
    void setup() { 
    
      DEBUG_SERIAL(115200);
      DEBUG_PRINTLN(F("Serial started"));
    
      lcdDisplay[0] = lcdDisplay0;
      lcdDisplay[1] = lcdDisplay1;
      lcdDisplay[2] = lcdDisplay2;
      lcdDisplay[3] = lcdDisplay3;
    
      gw.begin(getVariables, NODE_ID);
      gw.sendSketchInfo("WeatherDisplay", "2.5");
      gw.present(CHILD_ID_3, S_CUSTOM);
      gw.present(CHILD_ID_4, S_LIGHT);
    
      lcd.begin(16,2);
      createSweCaracters();
      
      lcd.setCursor(0, 0);
      lcd.print(F("Syncing Time"));
      lcd.setCursor(0, 1);
      int clockCounter = 0;
      while(timeStatus() == timeNotSet && clockCounter < 60) {
    	gw.process();
    	DEBUG_PRINTLN(F("getting Time"));
    	gw.requestTime(receiveTime);
    	gw.wait(1000);
    	lcd.print(".");
    	clockCounter++;
    	if (clockCounter > 16) {
    	  lcd.clear();
    	  lcd.print(F("**Failed Clock**"));
    	  lcd.setCursor(0,1);
    	  lcd.print(F("*Syncronization*"));
    	  gw.wait(2000);
    	  break;
    	}
      }
      lcd.clear();
      lastTime = millis();
    }
    
    void loop() {
      gw.process();
      if (millis() - lastClockSet >= CLOCK_SYNC_INTERVAL) {
    	DEBUG_PRINTLN(F("getting Time, again"));
    	gw.requestTime(receiveTime);
    	lastClockSet = millis();
      }
      if (millis() - lastTime >= DISPLAY_INTERVAL) {
    	state++;
    	if (state > STATES - 1) state = 0;
    	DEBUG_PRINT(F("State:")); 
    	DEBUG_PRINTLN(state);
    	lastTime += DISPLAY_INTERVAL;
    	fastClear();
    	lcdDisplay[state]();
      }
    }
    
    void fastClear() {
      lcd.setCursor(0,0);
      lcd.print(F("                "));
      lcd.setCursor(0,1);
      lcd.print(F("                "));
    }
    
    void lcdDisplay0() {
      lcd.setCursor(0,0);
      lcd.print(year());
      lcd.print("-"); 
      DEBUG_PRINT(F("Date: "));
      DEBUG_PRINT(year());
      DEBUG_PRINT("-");   
      if (month() < 10) {
    	lcd.print("0");
    	DEBUG_PRINT("0");
      }
      lcd.print(month());
      lcd.print("-");
      DEBUG_PRINT(month()); 
      DEBUG_PRINT("-"); 
      if (day() < 10) {
    	lcd.print("0");
    	DEBUG_PRINT("0");
      }
      lcd.print(day());
      DEBUG_PRINT(day()); 
      lcd.print(" ");
      DEBUG_PRINT(F("  Time: "));
      if (hour() < 10) {   
    	lcd.print("0");
    	DEBUG_PRINT("0");
      }
      lcd.print(hour()); 
      lcd.print(":");
      DEBUG_PRINT(hour());
      DEBUG_PRINT(":");
      if (minute() < 10) {
    	lcd.print("0");
    	DEBUG_PRINT("0");
      }
      lcd.print(minute());
      DEBUG_PRINTLN(minute());
    
      lcd.setCursor(0,1); 
      if (millis() - lastClockSet > FIVE_HOURS) {
    	lcd.print(F("Clk "));
    	lcd.print((millis()-lastClockSet)/ONE_MIN);
    	lcd.print(F(" min ago"));
    		DEBUG_PRINT(F(" (ClockSync > FIVE_HOURS): lastClockSet "));
    	DEBUG_PRINT((millis()-lastClockSet)/ONE_MIN);
    	DEBUG_PRINTLN(F(" min ago")); 
      }
      else if (millis() - lastWeatherUpdate > THREE_HOURS) {     // ( Controller weather update set to 1/hour )
    		lcd.print(F("Wtr "));
    	lcd.print((millis()-lastWeatherUpdate)/ONE_MIN);
    	lcd.print(F(" min ago"));
    	DEBUG_PRINT(F(" (lastWeatherUpdate > THREE_HOURS): lastWeatherUpdate "));
    	DEBUG_PRINT((millis()-lastWeatherUpdate)/ONE_MIN);
    	DEBUG_PRINTLN(F(" min ago")); 
      }
      else {
    	lcd.print(F("                "));
      }
    }
    
    void lcdDisplay1() {
      lcd.setCursor(0,0);
      //lcd.print(F("In T:"));
          lcd.print(F("In   "));
      lcd.print(indoorTemp); 
      lcd.print(char(223));
      DEBUG_PRINT(F("In T:")); 
      DEBUG_PRINT(indoorTemp);
      DEBUG_PRINT("C");
      //lcd.print(" H:");
          lcd.print("   ");
      lcd.print(indoorHumidity);
      lcd.print("%");
      DEBUG_PRINT(F(" H:"));
      DEBUG_PRINT(indoorHumidity);
      DEBUG_PRINTLN("%");
    
      lcd.setCursor(0,1);
      //lcd.print(F("Ut T:"));
      lcd.print(F("Ut   "));
          lcd.print(outdoorTemp); 
      lcd.print(char(223));
      DEBUG_PRINT(F("Out T:")); 
      DEBUG_PRINT(outdoorTemp);
      DEBUG_PRINT("C");
      //lcd.print(" H:");
      lcd.print("   ");
          lcd.print(outdoorHumidity);
      lcd.print("%");
      DEBUG_PRINT(F(" H:"));
      DEBUG_PRINT(outdoorHumidity);
      DEBUG_PRINTLN("%");  
    }
    
    void lcdDisplay2() {
      lcd.setCursor(0,0);
      //lcd.print(F("1  H:"));
      lcd.print(F("1    "));
          lcd.print(todayHigh); 
      lcd.print(char(223));
      DEBUG_PRINT(F("Today's High: "));
      DEBUG_PRINT(todayHigh);
      DEBUG_PRINT(F("C "));
      //lcd.print(F(" L:"));
      lcd.print(F("   "));
          lcd.print(todayLow); 
      lcd.print(char(223));
      DEBUG_PRINT(F("Today's Low: "));
      DEBUG_PRINT(todayLow);
      DEBUG_PRINTLN(F("C "));
    	
      lcd.setCursor(0,1);
      lcd.print(todayCondition);
      DEBUG_PRINT(F("Today's Weather (code): "));
      DEBUG_PRINTLN(todayConditionCode);    
    }
    
    void lcdDisplay3() {
      lcd.setCursor(0,0);
      //lcd.print(F("2  H:"));
      lcd.print(F("2    "));
          lcd.print(tomorrowHigh); 
      lcd.print(char(223));
      DEBUG_PRINT(F("Tomorrow's High: "));
      DEBUG_PRINT(tomorrowHigh);
      DEBUG_PRINT(F("C "));
      //lcd.print(F(" L:"));
      lcd.print(F("   "));
          lcd.print(tomorrowLow); 
      lcd.print(char(223));
      DEBUG_PRINT(F("Tomorrow's Low: "));
      DEBUG_PRINT(tomorrowLow);
      DEBUG_PRINTLN(F("C "));
    	
      lcd.setCursor(0,1);
      lcd.print(tomorrowCondition);
      DEBUG_PRINT(F("Tomorrow's Weather (code): "));
      DEBUG_PRINTLN(tomorrowConditionCode);  
    }
    
    void receiveTime(unsigned long time) {
      DEBUG_PRINT(F("Time value received: "));   // (UTC)
      DEBUG_PRINTLN(time);
      setTime(time); 
      DEBUG_PRINT(F("Hour received: "));   // (UTC)
      DEBUG_PRINTLN(hour());
          setTime(hour()+1,minute(),second(),day(),month(),year());  // Sets CET timezone  (GMT +1)
      DEBUG_PRINT(F("Time zone hour: "));   // (UTC)
      DEBUG_PRINTLN(hour());
      adjustDST(time);  // Sets DST (+1) if necessary
          DEBUG_PRINT(F("Adjusted DST hour: "));   // (UTC)
      DEBUG_PRINTLN(hour());
    }
    
    void adjustDST(unsigned long t) {
    	if ((year() >= 2015) && (year() < 2015+DST_YEARS)) {
    		if ((t > dstTable[year()-2015][0]) && (t < dstTable[year()-2015][1])) {
                                setTime(hour()+1,minute(),second(),day(),month(),year());
    		}
    	}
    }
    
    void getVariables(const MyMessage &message) {
      if (message.sensor == CHILD_ID_3) { 
    	if (message.type == V_VAR1) {
    	  outdoorTemp = atoi(message.data);
    	  DEBUG_PRINT(F("outdoorTemp recieved:"));
    	  DEBUG_PRINTLN(outdoorTemp);
    	}
    	if (message.type == V_VAR2) {
    	  outdoorHumidity = atoi(message.data);
    	  DEBUG_PRINT(F("outdoorHumidity recieved:"));
    	  DEBUG_PRINTLN(outdoorHumidity);
    	}
    	if (message.type == V_VAR3) {
    	  todayLow = atoi(message.data);
    	  DEBUG_PRINT(F("Received Today's LOW:"));
    	  DEBUG_PRINTLN(todayLow);
    	}
    	if (message.type == V_VAR4) {
    	  todayHigh = atoi(message.data);
    	  DEBUG_PRINT(F("Received Today's HIGH:"));
    	  DEBUG_PRINTLN(todayHigh);
    	}
    	if (message.type == V_VAR5)  {
    	  todayConditionCode = atoi(message.data);
    	  DEBUG_PRINT(F("Received today's Conditions: "));
    	  DEBUG_PRINT(todayConditionCode);
    	  DEBUG_PRINT("  ");
    	  getNewSweCond(todayConditionCode);
    	  todayCondition = condString;
    	  DEBUG_PRINTLN(todayCondition);
    	  lastWeatherUpdate = millis();
    	  DEBUG_PRINTLN(F(" and reset the lastWeatherUpdate-counter."));
    	}
      }
      if (message.sensor == CHILD_ID_4) {
    	if (message.type == V_STATUS) {
    	  int ledState = atoi(message.data);
    	  if (ledState > 0) {
    		lcd.backlight();
    	  }
    	  else {
    		lcd.noBacklight();
    	  }
    	}
    	if (message.type == V_VAR1) {
    	  indoorTemp = atoi(message.data);
    	  DEBUG_PRINT(F("indoorTemp recieved:"));
    	  DEBUG_PRINTLN(indoorTemp);
    	}
    	if (message.type == V_VAR2) {
    	  indoorHumidity = atoi(message.data);
    	  DEBUG_PRINT(F("indoorHumidity recieved:"));
    	  DEBUG_PRINTLN(indoorHumidity);
    	}
    	if (message.type == V_VAR3) {
    	  tomorrowConditionCode = atoi(message.data);
    	  DEBUG_PRINT(F("Received Tomorrow's Forecast: "));
    	  DEBUG_PRINT(tomorrowConditionCode);
    	  DEBUG_PRINT("  ");
    	  getNewSweCond(tomorrowConditionCode);
    	  tomorrowCondition = condString;
    	  DEBUG_PRINTLN(tomorrowCondition);
    	}
    	if (message.type == V_VAR4) {
    	  tomorrowHigh = atoi(message.data);
    	  DEBUG_PRINT(F("Received Tomorrow's HIGH:"));
    	  DEBUG_PRINTLN(tomorrowHigh);
    	}
    	if (message.type == V_VAR5) {
    	  tomorrowLow = atoi(message.data);
    	  DEBUG_PRINT(F("Received Tomorrow's LOW:"));
    	  DEBUG_PRINTLN(tomorrowLow);
    	}
      }
    }
    
    // Update the translated condition. 
    void getNewSweCond(int code) {
    	if (code > 0  && code < 48) {
    		strcpy_P(condString, (char*)pgm_read_word(&(condStrTable[code])));
    	}
    	else {
    		strcpy_P(condString, (char*)pgm_read_word(&(condStrTable[48])));
    	}
    }
    		
    		
    void createSweCaracters(){
      byte AwithRing[8] = {
    	 B00100,
    	 B01010,
    	 B01110,
    	 B00001,
    	 B01111,
    	 B10001,
    	 B01111,
       };
       
       byte AwithDots[8] = {
    	 B01010,
    	 B00000,
    	 B01110,
    	 B00001,
    	 B01111,
    	 B10001,
    	 B01111,
       };
       
       byte OwithDots[8] = {
    	 B01010,
    	 B00000,
    	 B01110,
    	 B10001,
    	 B10001,
    	 B10001,
    	 B01110,
       };
       
       byte CapitalAwithRing[8] = {
    	 B00100,
    	 B01010,
    	 B01110,
    	 B10001,
    	 B11111,
    	 B10001,
    	 B10001,
       };
       
       byte CapitalAwithDots[8] = {
    	 B01010,
    	 B00000,
    	 B01110,
    	 B10001,
    	 B11111,
    	 B10001,
    	 B10001,
       };
       
       byte CapitalOwithDots[8] = {
    	 B01010,
    	 B00000,
    	 B01110,
    	 B10001,
    	 B10001,
    	 B10001,
    	 B01110,
       };
       
       lcd.createChar(1, AwithRing);
       lcd.createChar(2, AwithDots);
       lcd.createChar(3, OwithDots);
       lcd.createChar(4, CapitalAwithRing);
       lcd.createChar(5, CapitalAwithDots);
       lcd.createChar(6, CapitalOwithDots);
    
    }


  • This is so great! Thank you!


  • Hardware Contributor

    Updated display node code to latest version (v2.5). The recent DST change passed without issues.


  • Hardware Contributor

    Yahoo world weather service seems to be have closed down. I got the last update the 24th.


  • Hardware Contributor

    So I changed the weather service provider to the FHEM-proven Openweather/wetter.com. I still only send the forecast conditions as codes to spare some MyS net traffic. I'm not as confident of my translations this time.

    I only post the node code below. For the Fhem part I just followed this Openweather wiki/guide and changed to new ReadingsVal in my myWeather2disp_ntfy macro posted above.

    	/* 
    	EgWeatherDisplay2.6
    	Weather and Forecast Display for FHEM with Swedish Conditions
    	By m26872, 20160329
    	changes from 2.5 to 2.6
    	- Changed weather condition codes and translations due to changed service provider (from yahoo to wetter.com)
    	changes from 2.4 to 2.5
    	- Automatic DST time for the next 4 years (controller always sync with UTC)
    	- Now use the gw.wait()
    	- Cleaned displays from some static info
    	- Updated child-ids, sensor and variable definitions to to aline with MySensors 1.5 and to avoid unwanted autocreations by fhem.
    	changes from 2.3 to 2.4
    	- New (correct) translations for some conditions
    	- Removed two unused "scene button" declarations.
    	*/
    
    	#define STATES 4
    	#define CLOCK_SYNC_INTERVAL 3600000UL  // 1 hour
    	#define DISPLAY_INTERVAL 3500UL  // 3,5s
    	#define FIVE_HOURS 18000000UL
    	#define THREE_HOURS 10800000UL
    	#define ONE_MIN 60000UL
    	#define DST_YEARS 5
    	#define Y2015_DST_ON 1427594400UL  // 2015-03-29 02:00
    	#define Y2015_DST_OFF 1445738400UL  // 2015-10-25 02:00     1445742000UL  // 2015-10-25 03:00
    	#define Y2016_DST_ON 1459044000UL  // 2016-03-27 02:00
    	#define Y2016_DST_OFF 1477792800UL  // 2016-10-30 02:00
    	#define Y2017_DST_ON 1490493600UL  // 2017-03-26 02:00
    	#define Y2017_DST_OFF 1509242400UL  // 2017-10-29 02:00
    	#define Y2018_DST_ON 1521943200UL  // 2018-03-25 02:00
    	#define Y2018_DST_OFF 1540692000UL  // 2018-10-28 02:00
    	#define Y2019_DST_ON 1553997600UL  // 2019-03-31 02:00
    	#define Y2019_DST_OFF 1572141600UL  // 2019-10-27 02:00
    	#define INDEX_LIST_LAST_POS 42
    
    	//#define DEBUG
    
    	#ifdef DEBUG
    	#define DEBUG_SERIAL(x) Serial.begin(x)
    	#define DEBUG_PRINT(x) Serial.print(x)
    	#define DEBUG_PRINTLN(x) Serial.println(x)
    	#else
    	#define DEBUG_SERIAL(x)
    	#define DEBUG_PRINT(x) 
    	#define DEBUG_PRINTLN(x) 
    	#endif
    
    	#include <avr/pgmspace.h>
    	#include <Wire.h>
    	#include <Time.h>
    	#include <SPI.h>
    	#include <MySensor.h>
    	#include <LiquidCrystal_I2C.h>
    
    	#define NODE_ID 112
    	#define CHILD_ID_3 3
    	#define CHILD_ID_4 4
    
    	LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address (Enl: https://arduino-info.wikispaces.com/LCD-Blue-I2C)
    
    	void (*lcdDisplay[STATES])();
    
    	byte state = STATES-1;
    	byte timeCounter = 0;
    	unsigned long lastTime;
    	unsigned long lastClockSet;
    	unsigned long lastClockReceived = 0UL;
    	unsigned long lastWeatherUpdate = 0UL;
    	int indoorTemp = -99;
    	int indoorHumidity = -99;
    	int outdoorTemp = -99;
    	int outdoorHumidity = -99;
    	int todayHigh = -99; 
    	int todayLow = -99;
    	int tomorrowHigh = -99; 
    	int tomorrowLow = -99;
    	int todayConditionCode = -99;
    	int tomorrowConditionCode = -99;
    	String todayCondition = "Not yet Reported";
    	String tomorrowCondition = "Not yet Reported";
    	unsigned long dstTable[DST_YEARS][2] = {{Y2015_DST_ON,Y2015_DST_OFF},{Y2016_DST_ON,Y2016_DST_OFF},{Y2017_DST_ON,Y2017_DST_OFF},{Y2018_DST_ON,Y2018_DST_OFF},{Y2019_DST_ON,Y2019_DST_OFF}}; 
    
    	MySensor gw;
    
    	MyMessage msgVAR1(CHILD_ID_3, V_VAR1);// outdoor temperature
    	MyMessage msgVAR2(CHILD_ID_3, V_VAR2);// outdoor humidity
    	MyMessage msgVAR3(CHILD_ID_3, V_VAR3);// today's low
    	MyMessage msgVAR4(CHILD_ID_3, V_VAR4);// today's high
    	MyMessage msgVAR5(CHILD_ID_3, V_VAR5);// conditions
    
    	MyMessage msgBackLight(CHILD_ID_4, V_STATUS);
    	MyMessage msgLVAR1(CHILD_ID_4, V_VAR1); // indoor temperature
    	MyMessage msgLVAR2(CHILD_ID_4, V_VAR2); // indoor humidity
    	MyMessage msgLVAR3(CHILD_ID_4, V_VAR3); // forecast for tomorrow 
    
    	// Swedish weather condition translations stored to flash. Special characters (å,ä,ö,Å,Ä,Ö) substituted with resp. LCD custom made character (01-06).	
    		const char cs0[] PROGMEM = "Soligt o klart";   // sonnig
    		const char cs1[] PROGMEM = "V\02xl. molnighet";   // leicht bewölkt
    		const char cs2[] PROGMEM = "\06verv\02g. mulet";    // wolkig
    		const char cs3[] PROGMEM = "Mulet";    // bedeckt
    		const char cs4[] PROGMEM = "Disigt";    // Nebel
    		const char cs5[] PROGMEM = "Duggregn";    // Sprühregen
    		const char cs6[] PROGMEM = "Regn";    // Regen
    		const char cs7[] PROGMEM = "Sn\03fall";    // Schnee
    		const char cs8[] PROGMEM = "Skurar";    // Schauer
    		const char cs9[] PROGMEM = "\04ska";    // Gewitter
    		const char cs10[] PROGMEM = "\06verv\02g. soligt";    // leicht bewölkt
    		const char cs20[] PROGMEM = "V\02xl. molnighet";    // wolkig
    		const char cs30[] PROGMEM = "\06verv\02g. mulet";    // bedeckt
    		const char cs40[] PROGMEM = "Dimma";    // Nebel
    		const char cs45[] PROGMEM = "Tjock dimma";    // Nebel
    		const char cs48[] PROGMEM = "Underkylt dis";    // Nebel mit Reifbildung 
    		const char cs49[] PROGMEM = "Underkylt dimma";    // Nebel mit Reifbildung 
    		const char cs50[] PROGMEM = "Duggregn";    // Sprühregen
    		const char cs51[] PROGMEM = "Enstaka duggregn";    //  leichter Sprühregen
    		const char cs53[] PROGMEM = "Duggregn";    // Sprühregen
    		const char cs55[] PROGMEM = "Rikligt duggregn";    // starker Sprühregen
    		const char cs56[] PROGMEM = "Underkylt d.regn";    // leichter Sprühregen, gefrierend
    		const char cs57[] PROGMEM = "Underkylt d.regn" ;    // starker Sprühregen, gefrierend
    		const char cs60[] PROGMEM = "L\02tt regn";    // leichter Regen
    		const char cs61[] PROGMEM = "L\02tt regn";    // leichter Regen
    		const char cs63[] PROGMEM = "Regn";    // mäßiger Regen
    		const char cs65[] PROGMEM = "Kraftigt regn";    // starker Regen
    		const char cs66[] PROGMEM = "L\02tt underk.regn";    // leichter Regen, gefrierend
    		const char cs67[] PROGMEM = "Underkylt regn";    // mäßiger od. starker Regen, gefrierend
    		const char cs68[] PROGMEM = "L\02tt sn\03bl.regn";    //  leichter Schnee-Regen 
    		const char cs69[] PROGMEM = "Sn\03bl.regn";    // starker Schnee-Regen
    		const char cs70[] PROGMEM = "L\02tt sn\03fall";    // leichter Schneefall 
    		const char cs71[] PROGMEM = "L\02tt sn\03fall";    // leichter Schneefall 
    		const char cs73[] PROGMEM = "Sn\03fall";    // mäßiger Schneefall
    		const char cs75[] PROGMEM = "Krafigt sn\03fall" ;    // starker Schneefall 
    		const char cs80[] PROGMEM = "Enstaka skurar";    // leichter Regen - Schauer 
    		const char cs81[] PROGMEM = "Skurar";    // Regen - Schauer 
    		const char cs82[] PROGMEM = "Spridda skurar";    // starker Regen - Schauer 
    		const char cs83[] PROGMEM = "Enstaka by/skur";    // leichter Schnee / Regen - Schauer 
    		const char cs84[] PROGMEM = "Spridda by/skur";    // starker Schnee / Regen - Schauer 
    		const char cs85[] PROGMEM = "Enstaka sn\03byar" ;    // leichter Schnee - Schauer 
    		const char cs86[] PROGMEM = "Spridda sn\03byar";    // mäßiger od. starker Schnee - Schauer
    		const char cs90[] PROGMEM = "\04ska" ;    // Gewitter 
    		const char cs95[] PROGMEM = "Enstaka \01ska" ;    //  	leichtes Gewitter 
    		const char cs96[] PROGMEM = "Spridd \01ska" ;    // starkes Gewitter 
    		const char cs999[] PROGMEM = "(Ingen uppgift)";    // Keine Angabe
    		const char cs9999[] PROGMEM = "(not available)";    // (3200) not available
    		
    		const char* const condStrTable[] PROGMEM = {cs0,cs1,cs2,cs3,cs4,cs5,cs6,cs7,cs8,cs9,cs10,cs20,cs30,cs40,cs45,cs48,cs49,cs50,cs51,cs53,cs55,cs57,cs60,cs61,cs63,cs65,cs66,cs67,cs68,cs69,cs70,cs71,cs73,cs75,cs80,cs81,cs82,cs83,cs84,cs85,cs86,cs90,cs95,cs96,cs999,cs9999};
    
    		char condString[17];
    		
    		const int indexList[] PROGMEM = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,20,30,40,45,48,49,50,51,53,55,57,60,61,63,65,66,67,68,69,70,71,73,75,80,81,82,83,84,85,86,90,95,96,999,9999};
    
    	void setup() { 
    
    	  DEBUG_SERIAL(115200);
    	  DEBUG_PRINTLN(F("Serial started"));
    
    	  lcdDisplay[0] = lcdDisplay0;
    	  lcdDisplay[1] = lcdDisplay1;
    	  lcdDisplay[2] = lcdDisplay2;
    	  lcdDisplay[3] = lcdDisplay3;
    
    	  gw.begin(getVariables, NODE_ID);
    	  gw.sendSketchInfo("WeatherDisplay", "2.6");
    	  gw.present(CHILD_ID_3, S_CUSTOM);
    	  gw.present(CHILD_ID_4, S_LIGHT);
    
    	  lcd.begin(16,2);
    	  createSweCaracters();
    	  
    	  lcd.setCursor(0, 0);
    	  lcd.print(F("Syncing Time"));
    	  lcd.setCursor(0, 1);
    	  int clockCounter = 0;
    	  while(timeStatus() == timeNotSet && clockCounter < 60) {
    		gw.process();
    		DEBUG_PRINTLN(F("getting Time"));
    		gw.requestTime(receiveTime);
    		gw.wait(1000);
    		lcd.print(".");
    		clockCounter++;
    		if (clockCounter > 16) {
    		  lcd.clear();
    		  lcd.print(F("**Failed Clock**"));
    		  lcd.setCursor(0,1);
    		  lcd.print(F("*Syncronization*"));
    		  gw.wait(2000);
    		  break;
    		}
    	  }
    	  lcd.clear();
    	  lastTime = millis();
    	}
    
    	void loop() {
    	  gw.process();
    	  if (millis() - lastClockSet >= CLOCK_SYNC_INTERVAL) {
    		DEBUG_PRINTLN(F("getting Time, again"));
    		gw.requestTime(receiveTime);
    		lastClockSet = millis();
    	  }
    	  if (millis() - lastTime >= DISPLAY_INTERVAL) {
    		state++;
    		if (state > STATES - 1) state = 0;
    		DEBUG_PRINT(F("State:")); 
    		DEBUG_PRINTLN(state);
    		lastTime += DISPLAY_INTERVAL;
    		fastClear();
    		lcdDisplay[state]();
    	  }
    	}
    
    	void fastClear() {
    	  lcd.setCursor(0,0);
    	  lcd.print(F("                "));
    	  lcd.setCursor(0,1);
    	  lcd.print(F("                "));
    	}
    
    	void lcdDisplay0() {
    	  lcd.setCursor(0,0);
    	  lcd.print(year());
    	  lcd.print("-"); 
    	  DEBUG_PRINT(F("Date: "));
    	  DEBUG_PRINT(year());
    	  DEBUG_PRINT("-");   
    	  if (month() < 10) {
    		lcd.print("0");
    		DEBUG_PRINT("0");
    	  }
    	  lcd.print(month());
    	  lcd.print("-");
    	  DEBUG_PRINT(month()); 
    	  DEBUG_PRINT("-"); 
    	  if (day() < 10) {
    		lcd.print("0");
    		DEBUG_PRINT("0");
    	  }
    	  lcd.print(day());
    	  DEBUG_PRINT(day()); 
    	  lcd.print(" ");
    	  DEBUG_PRINT(F("  Time: "));
    	  if (hour() < 10) {   
    		lcd.print("0");
    		DEBUG_PRINT("0");
    	  }
    	  lcd.print(hour()); 
    	  lcd.print(":");
    	  DEBUG_PRINT(hour());
    	  DEBUG_PRINT(":");
    	  if (minute() < 10) {
    		lcd.print("0");
    		DEBUG_PRINT("0");
    	  }
    	  lcd.print(minute());
    	  DEBUG_PRINTLN(minute());
    
    	  lcd.setCursor(0,1); 
    	  if (millis() - lastClockSet > FIVE_HOURS) {
    		lcd.print(F("Clk "));
    		lcd.print((millis()-lastClockSet)/ONE_MIN);
    		lcd.print(F(" min ago"));
    			DEBUG_PRINT(F(" (ClockSync > FIVE_HOURS): lastClockSet "));
    		DEBUG_PRINT((millis()-lastClockSet)/ONE_MIN);
    		DEBUG_PRINTLN(F(" min ago")); 
    	  }
    	  else if (millis() - lastWeatherUpdate > THREE_HOURS) {     // ( Controller weather update set to 1/hour )
    			lcd.print(F("Wtr "));
    		lcd.print((millis()-lastWeatherUpdate)/ONE_MIN);
    		lcd.print(F(" min ago"));
    		DEBUG_PRINT(F(" (lastWeatherUpdate > THREE_HOURS): lastWeatherUpdate "));
    		DEBUG_PRINT((millis()-lastWeatherUpdate)/ONE_MIN);
    		DEBUG_PRINTLN(F(" min ago")); 
    	  }
    	  else {
    		lcd.print(F("                "));
    	  }
    	}
    
    	void lcdDisplay1() {
    	  lcd.setCursor(0,0);
    	  //lcd.print(F("In T:"));
    		  lcd.print(F("In   "));
    	  lcd.print(indoorTemp); 
    	  lcd.print(char(223));
    	  DEBUG_PRINT(F("In T:")); 
    	  DEBUG_PRINT(indoorTemp);
    	  DEBUG_PRINT("C");
    	  //lcd.print(" H:");
    		  lcd.print("   ");
    	  lcd.print(indoorHumidity);
    	  lcd.print("%");
    	  DEBUG_PRINT(F(" H:"));
    	  DEBUG_PRINT(indoorHumidity);
    	  DEBUG_PRINTLN("%");
    
    	  lcd.setCursor(0,1);
    	  //lcd.print(F("Ut T:"));
    	  lcd.print(F("Ut   "));
    		  lcd.print(outdoorTemp); 
    	  lcd.print(char(223));
    	  DEBUG_PRINT(F("Out T:")); 
    	  DEBUG_PRINT(outdoorTemp);
    	  DEBUG_PRINT("C");
    	  //lcd.print(" H:");
    	  lcd.print("   ");
    		  lcd.print(outdoorHumidity);
    	  lcd.print("%");
    	  DEBUG_PRINT(F(" H:"));
    	  DEBUG_PRINT(outdoorHumidity);
    	  DEBUG_PRINTLN("%");  
    	}
    
    	void lcdDisplay2() {
    	  lcd.setCursor(0,0);
    	  //lcd.print(F("1  H:"));
    	  lcd.print(F("1    "));
    		  lcd.print(todayHigh); 
    	  lcd.print(char(223));
    	  DEBUG_PRINT(F("Today's High: "));
    	  DEBUG_PRINT(todayHigh);
    	  DEBUG_PRINT(F("C "));
    	  //lcd.print(F(" L:"));
    	  lcd.print(F("   "));
    		  lcd.print(todayLow); 
    	  lcd.print(char(223));
    	  DEBUG_PRINT(F("Today's Low: "));
    	  DEBUG_PRINT(todayLow);
    	  DEBUG_PRINTLN(F("C "));
    		
    	  lcd.setCursor(0,1);
    	  lcd.print(todayCondition);
    	  DEBUG_PRINT(F("Today's Weather (code): "));
    	  DEBUG_PRINTLN(todayConditionCode);    
    	}
    
    	void lcdDisplay3() {
    	  lcd.setCursor(0,0);
    	  //lcd.print(F("2  H:"));
    	  lcd.print(F("2    "));
    		  lcd.print(tomorrowHigh); 
    	  lcd.print(char(223));
    	  DEBUG_PRINT(F("Tomorrow's High: "));
    	  DEBUG_PRINT(tomorrowHigh);
    	  DEBUG_PRINT(F("C "));
    	  //lcd.print(F(" L:"));
    	  lcd.print(F("   "));
    		  lcd.print(tomorrowLow); 
    	  lcd.print(char(223));
    	  DEBUG_PRINT(F("Tomorrow's Low: "));
    	  DEBUG_PRINT(tomorrowLow);
    	  DEBUG_PRINTLN(F("C "));
    		
    	  lcd.setCursor(0,1);
    	  lcd.print(tomorrowCondition);
    	  DEBUG_PRINT(F("Tomorrow's Weather (code): "));
    	  DEBUG_PRINTLN(tomorrowConditionCode);  
    	}
    
    	void receiveTime(unsigned long time) {
    	  DEBUG_PRINT(F("Time value received: "));   // (UTC)
    	  DEBUG_PRINTLN(time);
    	  setTime(time); 
    	  DEBUG_PRINT(F("Hour received: "));   // (UTC)
    	  DEBUG_PRINTLN(hour());
    		  setTime(hour()+1,minute(),second(),day(),month(),year());  // Sets CET timezone  (GMT +1)
    	  DEBUG_PRINT(F("Time zone hour: "));   // (UTC)
    	  DEBUG_PRINTLN(hour());
    	  adjustDST(time);  // Sets DST (+1) if necessary
    		  DEBUG_PRINT(F("Adjusted DST hour: "));   // (UTC)
    	  DEBUG_PRINTLN(hour());
    	}
    	
    	void adjustDST(unsigned long t) {
    		if ((year() >= 2015) && (year() < 2015+DST_YEARS)) {
    			if ((t > dstTable[year()-2015][0]) && (t < dstTable[year()-2015][1])) {
    								setTime(hour()+1,minute(),second(),day(),month(),year());
    			}
    		}
    	}
    
    	void getVariables(const MyMessage &message) {
    	  if (message.sensor == CHILD_ID_3) { 
    		if (message.type == V_VAR1) {
    		  outdoorTemp = atoi(message.data);
    		  DEBUG_PRINT(F("outdoorTemp recieved:"));
    		  DEBUG_PRINTLN(outdoorTemp);
    		}
    		if (message.type == V_VAR2) {
    		  outdoorHumidity = atoi(message.data);
    		  DEBUG_PRINT(F("outdoorHumidity recieved:"));
    		  DEBUG_PRINTLN(outdoorHumidity);
    		}
    		if (message.type == V_VAR3) {
    		  todayLow = atoi(message.data);
    		  DEBUG_PRINT(F("Received Today's LOW:"));
    		  DEBUG_PRINTLN(todayLow);
    		}
    		if (message.type == V_VAR4) {
    		  todayHigh = atoi(message.data);
    		  DEBUG_PRINT(F("Received Today's HIGH:"));
    		  DEBUG_PRINTLN(todayHigh);
    		}
    		if (message.type == V_VAR5)  {
    		  todayConditionCode = atoi(message.data);
    		  DEBUG_PRINT(F("Received today's Conditions: "));
    		  DEBUG_PRINT(todayConditionCode);
    		  DEBUG_PRINT("  ");
    		  getNewSweCond(todayConditionCode);
    		  todayCondition = condString;
    		  DEBUG_PRINTLN(todayCondition);
    		  lastWeatherUpdate = millis();
    		  DEBUG_PRINTLN(F(" and reset the lastWeatherUpdate-counter."));
    		}
    	  }
    	  if (message.sensor == CHILD_ID_4) {
    		if (message.type == V_STATUS) {
    		  int ledState = atoi(message.data);
    		  if (ledState > 0) {
    			lcd.backlight();
    		  }
    		  else {
    			lcd.noBacklight();
    		  }
    		}
    		if (message.type == V_VAR1) {
    		  indoorTemp = atoi(message.data);
    		  DEBUG_PRINT(F("indoorTemp recieved:"));
    		  DEBUG_PRINTLN(indoorTemp);
    		}
    		if (message.type == V_VAR2) {
    		  indoorHumidity = atoi(message.data);
    		  DEBUG_PRINT(F("indoorHumidity recieved:"));
    		  DEBUG_PRINTLN(indoorHumidity);
    		}
    		if (message.type == V_VAR3) {
    		  tomorrowConditionCode = atoi(message.data);
    		  DEBUG_PRINT(F("Received Tomorrow's Forecast: "));
    		  DEBUG_PRINT(tomorrowConditionCode);
    		  DEBUG_PRINT("  ");
    		  getNewSweCond(tomorrowConditionCode);
    		  tomorrowCondition = condString;
    		  DEBUG_PRINTLN(tomorrowCondition);
    		}
    		if (message.type == V_VAR4) {
    		  tomorrowHigh = atoi(message.data);
    		  DEBUG_PRINT(F("Received Tomorrow's HIGH:"));
    		  DEBUG_PRINTLN(tomorrowHigh);
    		}
    		if (message.type == V_VAR5) {
    		  tomorrowLow = atoi(message.data);
    		  DEBUG_PRINT(F("Received Tomorrow's LOW:"));
    		  DEBUG_PRINTLN(tomorrowLow);
    		}
    	  }
    	}
    
    	// Update the translated condition. 
    	void getNewSweCond(int code) {
    		int cci = csCodeIndex(code);
    		DEBUG_PRINT("cci: ");
    		DEBUG_PRINTLN(cci);
    		strcpy_P(condString, (char*)pgm_read_word(&(condStrTable[cci])));		
    	}
    			
    	uint8_t csCodeIndex(int csCode) {
    		uint8_t i = 0;
    		while ( (pgm_read_word_near(indexList + i) < csCode) && (i < INDEX_LIST_LAST_POS) ) { 
    			i++;
    		}
    		return i;
    	}
    			
    	void createSweCaracters(){
    	  byte AwithRing[8] = {
    		 B00100,
    		 B01010,
    		 B01110,
    		 B00001,
    		 B01111,
    		 B10001,
    		 B01111,
    	   };
    	   
    	   byte AwithDots[8] = {
    		 B01010,
    		 B00000,
    		 B01110,
    		 B00001,
    		 B01111,
    		 B10001,
    		 B01111,
    	   };
    	   
    	   byte OwithDots[8] = {
    		 B01010,
    		 B00000,
    		 B01110,
    		 B10001,
    		 B10001,
    		 B10001,
    		 B01110,
    	   };
    	   
    	   byte CapitalAwithRing[8] = {
    		 B00100,
    		 B01010,
    		 B01110,
    		 B10001,
    		 B11111,
    		 B10001,
    		 B10001,
    	   };
    	   
    	   byte CapitalAwithDots[8] = {
    		 B01010,
    		 B00000,
    		 B01110,
    		 B10001,
    		 B11111,
    		 B10001,
    		 B10001,
    	   };
    	   
    	   byte CapitalOwithDots[8] = {
    		 B01010,
    		 B00000,
    		 B01110,
    		 B10001,
    		 B10001,
    		 B10001,
    		 B01110,
    	   };
    	   
    	   lcd.createChar(1, AwithRing);
    	   lcd.createChar(2, AwithDots);
    	   lcd.createChar(3, OwithDots);
    	   lcd.createChar(4, CapitalAwithRing);
    	   lcd.createChar(5, CapitalAwithDots);
    	   lcd.createChar(6, CapitalOwithDots);
    
    	}


  • Yahoo weather in fhem is fixed again...
    W


  • Hardware Contributor

    @vorowski Thx for the info. It's been down before so I don't mind trying something else anyway. Maybe I can start presenting and logging forecasts from different prividers and then evaluate them 😀


Log in to reply
 

Looks like your connection to MySensors Forum was lost, please wait while we try to reconnect.