This commit is contained in:
Dustin Brunner 2021-03-08 16:03:38 +01:00
commit 0dc1fa6562
13 changed files with 602 additions and 0 deletions

View File

@ -0,0 +1,210 @@
[
{
"id": "5b547237.9a52bc",
"type": "tab",
"label": "Weather Display",
"disabled": false,
"info": ""
},
{
"id": "a2ac16c5.ad4e58",
"type": "mqtt in",
"z": "5b547237.9a52bc",
"name": "",
"topic": "wetter_display/get",
"qos": "2",
"datatype": "auto",
"broker": "3bfdb428.8d8e3c",
"x": 170,
"y": 140,
"wires": [
[
"20125342.344d4c"
]
]
},
{
"id": "72a13cf3.9527c4",
"type": "mqtt out",
"z": "5b547237.9a52bc",
"name": "",
"topic": "wetter_display/set",
"qos": "2",
"retain": "false",
"broker": "3bfdb428.8d8e3c",
"x": 1090,
"y": 140,
"wires": []
},
{
"id": "20125342.344d4c",
"type": "function",
"z": "5b547237.9a52bc",
"name": "Read Global Variables",
"func": "var output = {};\noutput.topic = \"Wetter_Display_out\";\n\noutput.payload = { \n \"Temp_2m\" : global.get(\"Temperatur_2m\"), \n \"Temp_0m\" : global.get(\"Temperatur_Boden\"),\n \"Pressure\" : global.get(\"Luftdruck\"),\n \"Humidity\" : global.get(\"Luftfeuchte_rel\"),\n \"Dewpoint\" : global.get(\"Taupunkt\"),\n \"Luminosity\" : global.get(\"Helligkeit_lux\"),\n \"Wind_kmh\" : global.get(\"Wind_kmh\"),\n \"Wind_r\" : global.get(\"Windr_wort\")\n};\n\nreturn output;",
"outputs": 1,
"noerr": 0,
"x": 600,
"y": 140,
"wires": [
[
"b9edddb6.383fa"
]
]
},
{
"id": "12b19c78.f0786c",
"type": "inject",
"z": "5b547237.9a52bc",
"name": "",
"topic": "",
"payload": "1",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 210,
"y": 240,
"wires": [
[
"42d784a7.9a7da4"
]
]
},
{
"id": "4c2cf417.9ae95c",
"type": "debug",
"z": "5b547237.9a52bc",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"x": 1070,
"y": 200,
"wires": []
},
{
"id": "b9edddb6.383fa",
"type": "json",
"z": "5b547237.9a52bc",
"name": "",
"property": "payload",
"action": "",
"pretty": false,
"x": 790,
"y": 140,
"wires": [
[
"4c2cf417.9ae95c",
"72a13cf3.9527c4"
]
]
},
{
"id": "42d784a7.9a7da4",
"type": "openweathermap",
"z": "5b547237.9a52bc",
"name": "Current Weather",
"wtype": "current",
"lon": "",
"lat": "",
"city": "Chemnitz",
"country": "Germany",
"language": "de",
"x": 390,
"y": 240,
"wires": [
[
"67d683df.1e7e6c"
]
]
},
{
"id": "67d683df.1e7e6c",
"type": "function",
"z": "5b547237.9a52bc",
"name": "Processing",
"func": "var output = {};\noutput.topic = \"Wetter_Display_out\";\n\nvar degToCard = function(deg){\nif (deg>11.25 && deg<=33.75){\nreturn \"NNO\";\n }else if (deg>33.75 && deg<56.25){\nreturn \"NO\";\n }else if (deg>56.25 && deg<78.75){\nreturn \"OON\";\n }else if (deg>78.75 && deg<101.25){\nreturn \"O\";\n }else if (deg>101.25 && deg<123.75){\nreturn \"OOS\";\n }else if (deg>123.75 && deg<146.25){\nreturn \"SO\";\n }else if (deg>146.25 && deg<168.75){\nreturn \"SSO\";\n }else if (deg>168.75 && deg<191.25){\nreturn \"S\";\n }else if (deg>191.25 && deg<213.75){\nreturn \"SSW\";\n }else if (deg>213.75 && deg<236.25){\nreturn \"SW\";\n }else if (deg>236.25 && deg<258.75){\nreturn \"WWS\";\n }else if (deg>258.75 && deg<281.25){\nreturn \"W\";\n }else if (deg>281.25 && deg<303.75){\nreturn \"WWN\";\n }else if (deg>303.75 && deg<326.25){\nreturn \"NW\";\n }else if (deg>326.25 && deg<348.75){\nreturn \"NNW\";\n }else{\nreturn \"N\"; \n }\n}\n\n\noutput.payload = { \n \"Temp_2m\" : msg.payload.tempc, \n \"Temp_0m\" : \"0\",\n \"Pressure\" : msg.payload.pressure,\n \"Humidity\" : msg.payload.humidity,\n \"Dewpoint\" : \"0\",\n \"Luminosity\" : \"0\",\n \"Wind_kmh\" : msg.payload.windspeed,\n \"Wind_r\" : degToCard(msg.payload.winddirection)\n};\n\nreturn output;",
"outputs": 1,
"noerr": 0,
"x": 570,
"y": 240,
"wires": [
[
"951d81bf.31f23"
]
]
},
{
"id": "129a08cd.8b738f",
"type": "comment",
"z": "5b547237.9a52bc",
"name": "Open Weather API Source",
"info": "Modified from:\nhttps://flows.nodered.org/flow/b5b7d5da14d24e71de447e6aa290937e/in/dbKdTXPTnHBx ",
"x": 410,
"y": 280,
"wires": []
},
{
"id": "cb2cc43f.e09de8",
"type": "inject",
"z": "5b547237.9a52bc",
"name": "",
"topic": "",
"payload": "1",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 390,
"y": 100,
"wires": [
[
"20125342.344d4c"
]
]
},
{
"id": "951d81bf.31f23",
"type": "json",
"z": "5b547237.9a52bc",
"name": "",
"property": "payload",
"action": "",
"pretty": false,
"x": 790,
"y": 240,
"wires": [
[
"4c2cf417.9ae95c",
"72a13cf3.9527c4"
]
]
},
{
"id": "3bfdb428.8d8e3c",
"type": "mqtt-broker",
"z": "",
"name": "MQTT_SERVER",
"broker": "192.168.123.456",
"port": "1883",
"clientid": "",
"usetls": false,
"compatmode": true,
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"willTopic": "",
"willQos": "0",
"willPayload": ""
}
]

Binary file not shown.

Binary file not shown.

48
README.md Normal file
View File

@ -0,0 +1,48 @@
# MQTT-Weather-display
Nokia 5110 MQTT Weather Display (Also works with Openweathermap)
This is how to build a MQTT Weather Display based on the Nokia 5110 Display and an ESP8266 to show the current temperature and other weather data.
<img src="pictures/Display_1.jpg" width="30%"> <img src="pictures/Display_2.jpg" width="30%"> <img src="pictures/Case_back.jpg" width="30%">
# How it works
The display is sending a request via MQTT to the server, where this request is processed on Node Red. Node Red responds with an JSON message, which contains the weather data. This data is then displayed on the Nokia 5110 display.
# Hardware
The schematic looks like this:
<img src="pictures/schematic.png" width="80%">
The whole system is mounted in a 3D-printed enclosure which I found on thingiverse (https://www.thingiverse.com/thing:3725377). I modified it a bit to fit my needs. You can find the stl files on github.
The Case is designed to fit for a WEMOS D1 Mini Board.
The device also has a pushbutton with the following function:
- short press: activate LCD backlight for a defined time
- long press: show page two with additional measurements and activate LCD backlight
- double press: force the display to update the values
# Software
You can find the software for the ESP on Github. It uses some external libraries which are linked to in the code.
<br>**!!!!! IMORTANT: I noticed that you have to increase the MQTT_MAX_PACKET_SIZE in the PubSubClient.h file to at least 1024**
<br>(Located on Windows at `C:\Users\*YOUR_USERNAME*\Documents\Arduino\libraries\pubsubclient-master\src\PubSubClient.h`).
<br>Otherwise the display wont receive the messages because they are quiet long.
The Node Red flow is quite simple:
<br><img src="pictures/Node_Red_Flow.png" width="100%">
<br>
You can import it using the given json file on Github. Notice that I get the weather data from my own weather station which is stored in global variables in Node Red.
I also included another flow which will make the display work getting the data from the Openweathermap API (Source: https://flows.nodered.org/flow/b5b7d5da14d24e71de447e6aa290937e/in/dbKdTXPTnHBx . This page also describes how to setup the API). You just need to delete the “Read global Variables” function and connect the Openweathermap function instead. Dont forget to set your Location correctly.
# Power Consumption
After a short time with now WLAN traffic the ESP goes into an auto sleep mode, where the power consumption is reduced to an average value of around 40mA. This mode is enabled by default. It wakes up every view milliseconds to check for incoming traffic. This looks like this:
<img src="pictures/Power_Consumption.png" width="50%">
I also tried to switch off the WIFI completely while not receiving any messages but this didnt work out and the ESP often crashes.
### I hope you like this project!
<p xmlns:dct="http://purl.org/dc/terms/" xmlns:cc="http://creativecommons.org/ns#" class="license-text">This work by <span property="cc:attributionName">Dustin Brunner</span> is licensed under <a rel="license" href="https://creativecommons.org/licenses/by/4.0">CC BY 4.0<img style="height:15px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg?ref=chooser-v1" /><img style="height:15px!important;margin-left:3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg?ref=chooser-v1" /></a></p>
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons Lizenzvertrag" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a><br />Dieses Werk von <span xmlns:cc="http://creativecommons.org/ns#" property="cc:attributionName">Dustin Brunner</span> ist lizenziert unter einer <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Namensnennung 4.0 International Lizenz</a>.

View File

@ -0,0 +1,216 @@
/*
WARNING:
If you are not receiving the Json Messages you probably have to increase the
MQTT_MAX_PACKET_SIZE in the PubSubClient.h file to at least 1024
(Located on Windows at C:\Users\*YOUR_USERNAME*\Documents\Arduino\libraries\pubsubclient-master\src\PubSubClient.h)
*/
#include <SPI.h>
#include <ESP8266WiFi.h>
#include <Adafruit_PCD8544.h> // https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library
#include <Adafruit_GFX.h> // https://github.com/adafruit/Adafruit-GFX-Library
#include <PubSubClient.h> // https://github.com/knolleary/pubsubclient
#include <OneButton.h> // https://github.com/mathertel/OneButton
#include <ArduinoJson.h> // https://github.com/bblanchon/ArduinoJson
const char *ssid = "----WIFI_SSID_HERE----";
const char *password = "----WIFI_PASSWORD_HERE----";
//MQTT Server
const char *mqtt_server = "----MQTT_SERVER_IP_HERE----";
const char *mqtt_user = "----MQTT_USERNAME_HERE----";
const char *mqtt_pass = "----MQTT_PASSWORD_HERE----";
int contrast = 65;
unsigned long display_light_max = 10000; // Values in ms
unsigned long display_2_max = 10000;
unsigned long update_time_max = 600000; // 600000 ms = 10 min
const int buttonpin = D6;
const int backlightpin = D4;
Adafruit_PCD8544 display = Adafruit_PCD8544(D5, D7, D3, D2, D1);
String update = "-";
String temp_2m = "TT.T";
String humidity = "FF.F";
String pressure = "DDDD.D";
String temp_0m = "T0.T";
String dewpoint = "tp.t";
String luminosity = "HHHHH.H";
String wind = "WW.W";
String windr = "WRWR";
bool startup = true;
unsigned long update_time = 0;
bool display_light = false;
unsigned long display_light_time = 0;
bool display_2 = false;
unsigned long display_2_time = 0;
int error = 0;
WiFiClient espClient;
PubSubClient client(espClient);
StaticJsonBuffer<1024> jsonBuffer;
OneButton button = OneButton(
buttonpin, // Input pin for the button
true, // Button is active LOW
true // Enable internal pull-up resistor
);
void setup()
{
pinMode(backlightpin, OUTPUT);
digitalWrite(backlightpin, LOW); //LOW = Light on!
button.attachClick(button_click);
button.attachLongPressStart(button_long);
button.attachDoubleClick(button_doubleclick);
display.begin();
display.setContrast(contrast);
display.setTextSize(2);
display.clearDisplay();
display.setTextColor(BLACK);
display.setCursor(5, 0);
display.print("Wetterstation");
display.setTextSize(1);
display.setCursor(5, 35);
display.print("Starting ...");
display.display();
delay(1000);
digitalWrite(backlightpin, HIGH);
delay(1000);
digitalWrite(backlightpin, LOW);
delay(1000);
digitalWrite(backlightpin, HIGH);
delay(1000);
digitalWrite(backlightpin, LOW);
display.clearDisplay();
display.setCursor(5, 0);
display.print("Wetterstation");
display.setCursor(1, 10);
display.print("Connecting Wifi");
display.setCursor(1, 20);
display.display();
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
display.print(".");
display.display();
delay(500);
}
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
reconnect();
display.clearDisplay();
display.setCursor(5, 0);
display.print("Wetterstation");
display.setCursor(25, 10);
display.print("Wifi");
display.setCursor(15, 30);
display.print("connected");
display.display();
delay(1000);
digitalWrite(backlightpin, HIGH);
}
void button_doubleclick()
{
display.clearDisplay();
display.setTextColor(BLACK);
display.setTextSize(1);
display.setCursor(5, 25);
display.print("Updating ...");
display.display();
delay(100);
update_time = millis() + update_time_max + 1;
}
void button_click()
{
digitalWrite(backlightpin, LOW);
display_light_time = millis();
display_light = true;
}
void button_long()
{
digitalWrite(backlightpin, LOW);
display_light_time = millis();
display_light = true;
display_page2();
display_2_time = millis();
display_2 = true;
}
void loop()
{
button.tick();
if (!client.connected())
reconnect();
client.loop();
if (millis() - update_time > update_time_max || startup)
{
startup = false;
error = 3;
display.setCursor(0, 10);
display.print("U");
display.display();
delay(300);
client.publish("wetter_display/get", "1");
update_time = millis();
}
if (error == 2)
{
display_error("Message decoding Error");
error = 0;
}
else if (error == 1)
{
updatedisplay();
error = 0;
}
else if (error == 3 && millis() - update_time > 5000)
{
display_error("No Response from MQTT server");
error = 0;
}
if (display_light && (millis() - display_light_time > display_light_max))
{
digitalWrite(backlightpin, HIGH);
display_light = false;
}
if (display_2 && (millis() - display_2_time > display_2_max))
{
updatedisplay();
display_2 = false;
}
delay(100);
}

View File

@ -0,0 +1,86 @@
void updatedisplay()
{
if (update == "-") update = "--";
else if (update == "--") update = "---";
else if (update == "---") update = "----";
else if (update == "----") update = "-----";
else if (update == "-----") update = "-";
display.clearDisplay();
display.setTextColor(BLACK);
display.setTextSize(1);
display.setCursor(0, 0);
display.print("Temp");
display.setCursor(28, 0);
display.setTextSize(2);
display.print(temp_2m); //Temperature
display.setTextSize(1);
display.setCursor(12, 10);
display.print("*C");
display.setCursor(0, 18);
display.print("Feu");
display.setCursor(28, 18);
display.print(humidity); //Humidity
display.print(" %");
display.setCursor(0, 28);
display.print("Dr");
display.setCursor(28, 28);
display.print(pressure); //Pressure
display.print("hPa");
display.setCursor(0, 38);
display.print("Wind");
display.setCursor(28, 38);
display.print(wind); //Windspeed
display.print("km/h");
display.display();
}
void display_page2()
{
display.clearDisplay();
display.setTextColor(BLACK);
display.setTextSize(1);
display.setCursor(0, 0);
display.print("Windr");
display.setCursor(32, 0);
display.print(windr); //Wind direction
display.setCursor(0, 10);
display.print("TempB");
display.setCursor(32, 10);
display.print(temp_0m); //Temperature 0m
display.print(" *C");
display.setCursor(0, 20);
display.print("Taup");
display.setCursor(28, 20);
display.print(dewpoint); //Dewpoint
display.setCursor(0, 30);
display.print("Hell");
display.setCursor(28, 30);
display.print(luminosity); //Luminosity
display.setCursor(0, 40);
display.print(update); //Windrichtung
display.display();
}
void display_error(String error)
{
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(BLACK);
display.setCursor(5, 0);
display.print("Error");
display.setTextSize(1);
display.setCursor(0, 20);
display.print(error);
display.display();
}

View File

@ -0,0 +1,42 @@
void callback(String topic, byte* message, unsigned int length)
{
String messageTemp;
for (int i = 0; i < length; i++)
messageTemp += (char)message[i];
if (topic == "wetter_display/set")
{
JsonObject& json = jsonBuffer.parseObject(messageTemp);
if (!json.success()) {
error = 2;
return;
}
temp_2m = json["Temp_2m"].as<String>();
temp_0m = json["Temp_0m"].as<String>();
pressure = json["Pressure"].as<String>();
humidity = json["Humidity"].as<String>();
dewpoint = json["Dewpoint"].as<String>();
luminosity = json["Luminosity"].as<String>();
wind = json["Wind_kmh"].as<String>();
windr = json["Wind_r"].as<String>();
error = 1;
jsonBuffer.clear();
}
}
void reconnect()
{
while (!client.connected())
{
if (client.connect("WetterDisplay", mqtt_user, mqtt_pass))
client.subscribe("wetter_display/set");
else
{
display_error("MQTT Error");
delay(5000);
}
}
}

BIN
pictures/Case_back.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

BIN
pictures/Display_1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

BIN
pictures/Display_2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

BIN
pictures/Node_Red_Flow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
pictures/schematic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB