Hallo,
Ich würde euch gerne mein kleines Projekt vorstellen. Ich habe mir ein Display gebaut, welches ich an der Haustüre innen verbauen will, so dass ich auf einen Blick sehe ob z.B. noch Fenster offen sind. Ausserdem habe ich gleich noch eine Anwesenheitserkennung mit aufgebaut.
Eingesetzt habe ich:
- Olimex ESP32-POE-ISO Board: Bluetooth Low Energy Scanner und Ansteuerung für das Display
- Waveshare 400x300, 4.2inch E-Ink raw display (Artikelnr. 13186)
- Waveshare 4.2inch e-Paper Raw Panel Case (Artikelnr. 16116
- Waveshare Universal e-Paper Raw Panel Driver HAT (Artikelnr 13512)
- Gigaset G-Tag Bluetooth Low Energy beacons
Das Setup ist folgendes:
Das ESP32 Board habe ich mit ESPHome programmiert. Die Verbindung zum iobroker geht über mqtt. Das ESP32 Board wird über POE mit Strom und LAN versorgt. Am Ende wird das in eine Unterputz-Installationsdose versenkt und das Display auf einer Blindabdeckung auf dem Schalterrahmen befestigt.
Hier der relevante Code:
Die yaml-Datei für ESPhome:
esphome:
name: bt_eingang
platform: ESP32
board: esp32-poe-iso
ethernet:
type: LAN8720
mdc_pin: GPIO23
mdio_pin: GPIO18
clk_mode: GPIO17_OUT
phy_addr: 0
power_pin: GPIO12
font:
- file: "ubuntu.ttf"
id: my_font
size: 20
spi:
clk_pin: 14
mosi_pin: 4
esp32_ble_tracker:
binary_sensor:
- platform: ble_presence
mac_address: 58:9E:XX:XX:XX:XX
name: "Tracker white"
id: track_w
- platform: ble_presence
mac_address: 58:9E:XX:XX:XX:XX
name: "Tracker black"
id: track_b
text_sensor:
- platform: mqtt_subscribe
name: "Aussentemperatur"
id: temp_out
topic: bt_eingang/display/temp_out
- platform: mqtt_subscribe
name: "Headline"
id: fc_symbol
topic: bt_eingang/display/headline
- platform: mqtt_subscribe
name: "Line 2OG Licht"
id: line_2OG_licht
topic: bt_eingang/display/line_2OG_licht
- platform: mqtt_subscribe
name: "Line 2OG Fenster"
id: line_2OG_fenster
topic: bt_eingang/display/line_2OG_fenster
- platform: mqtt_subscribe
name: "Line 1OG Licht"
id: line_1OG_licht
topic: bt_eingang/display/line_1OG_licht
- platform: mqtt_subscribe
name: "Line 1OG Fenster"
id: line_1OG_fenster
topic: bt_eingang/display/line_1OG_fenster
- platform: mqtt_subscribe
name: "Line EG Fenster"
id: line_EG_fenster
topic: bt_eingang/display/line_EG_fenster
- platform: mqtt_subscribe
name: "Line EG Licht"
id: line_EG_licht
topic: bt_eingang/display/line_EG_licht
- platform: mqtt_subscribe
name: "Anwesenheit"
id: presence_string
topic: bt_eingang/display/presence_string
#Bilder aus dem DasWetter-Adapter invertiert und als jpg ohne Transparenz gespeichert
image:
- file: "icons/tiempo-weather/galeria5/PNG/mine/1.jpg"
id: image_1
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/2.jpg"
id: image_2
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/3.jpg"
id: image_3
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/4.jpg"
id: image_4
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/5.jpg"
id: image_5
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/6.jpg"
id: image_6
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/7.jpg"
id: image_7
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/8.jpg"
id: image_8
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/9.jpg"
id: image_9
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/10.jpg"
id: image_10
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/11.jpg"
id: image_11
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/12.jpg"
id: image_12
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/13.jpg"
id: image_13
resize: 60x60
- file: "icons/tiempo-weather/galeria5/PNG/mine/14.jpg"
id: image_14
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/15.jpg"
id: image_15
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/16.jpg"
id: image_16
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/17.jpg"
id: image_17
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/18.jpg"
id: image_18
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/19.jpg"
id: image_19
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/20.jpg"
id: image_20
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/21.jpg"
id: image_21
resize: 40x40
- file: "icons/tiempo-weather/galeria5/PNG/mine/22.jpg"
id: image_22
resize: 40x40
display:
- platform: waveshare_epaper
cs_pin: 16
dc_pin: 15
busy_pin: 13
reset_pin: 2
model: 4.20in
update_interval: 3600s #Displayrefresh flickert bei dem Display leider
id: my_display
lambda: |-
it.printf(10,20, id(my_font), "Temperatur: %s", id(temp_out).state.c_str());
it.print(250,10, id(my_font), "Vorhersage:");
if (id(fc_symbol).state == "1") { it.image(360, 0, id(image_1)); };
if (id(fc_symbol).state == "2") { it.image(360, 0, id(image_2)); };
if (id(fc_symbol).state == "3") { it.image(360, 0, id(image_3)); };
if (id(fc_symbol).state == "4") { it.image(360, 0, id(image_4)); };
if (id(fc_symbol).state == "5") { it.image(360, 0, id(image_5)); };
if (id(fc_symbol).state == "6") { it.image(360, 0, id(image_6)); };
if (id(fc_symbol).state == "7") { it.image(360, 0, id(image_7)); };
if (id(fc_symbol).state == "8") { it.image(360, 0, id(image_8)); };
if (id(fc_symbol).state == "9") { it.image(360, 0, id(image_9)); };
if (id(fc_symbol).state == "10") { it.image(360, 0, id(image_10)); };
if (id(fc_symbol).state == "11") { it.image(360, 0, id(image_11)); };
if (id(fc_symbol).state == "12") { it.image(360, 0, id(image_12)); };
if (id(fc_symbol).state == "13") { it.image(360, 0, id(image_13)); };
if (id(fc_symbol).state == "14") { it.image(360, 0, id(image_14)); };
if (id(fc_symbol).state == "15") { it.image(360, 0, id(image_15)); };
if (id(fc_symbol).state == "16") { it.image(360, 0, id(image_16)); };
if (id(fc_symbol).state == "17") { it.image(360, 0, id(image_17)); };
if (id(fc_symbol).state == "18") { it.image(360, 0, id(image_18)); };
if (id(fc_symbol).state == "19") { it.image(360, 0, id(image_19)); };
if (id(fc_symbol).state == "20") { it.image(360, 0, id(image_20)); };
if (id(fc_symbol).state == "21") { it.image(360, 0, id(image_21)); };
if (id(fc_symbol).state == "22") { it.image(360, 0, id(image_22)); };
//geht sicher auch schöner in einer Zeile Code...
it.line(0, 47, 400, 47);
//Table
it.line(100, 110, 300, 110);
it.line(100, 150, 300, 150);
it.line(100, 190, 300, 190);
it.line(100, 230, 300, 230);
it.line(200, 110, 200, 230);
it.line(100, 110, 100, 230);
it.line(300, 110, 300, 230);
//Lastline
it.line(0, 255, 400, 255);
it.print(130,80,id(my_font), "Licht");
it.print(220,80,id(my_font), "Fenster");
it.print(50,120,id(my_font), "2 OG");
it.print(50,160,id(my_font), "1 OG");
it.print(70,200,id(my_font), "EG");
it.printf(110,130, id(my_font), "%s", id(line_2OG_licht).state.c_str());
it.printf(210,130, id(my_font), "%s", id(line_2OG_fenster).state.c_str());
it.printf(110,170, id(my_font), "%s", id(line_1OG_licht).state.c_str());
it.printf(210,170, id(my_font), "%s", id(line_1OG_fenster).state.c_str());
it.printf(110,210, id(my_font), "%s", id(line_EG_licht).state.c_str());
it.printf(210,210, id(my_font), "%s", id(line_EG_fenster).state.c_str());
it.printf(10,275,id(my_font), "Anwesenheit: %s", id(presence_string).state.c_str());
# Enable logging
logger:
mqtt:
broker: #IP vom iobroker
username: #wie in iobroker mqtt adapter
password: #wie in iobroker mqtt adapter
client_id: bt_Eingang
# log_topic: bt_eingang/log/
on_message: # Manueller refresh des Displays bei Änderung
topic: bt_eingang/display/refresh
payload: "ON"
then:
- component.update: my_display
ota:
Das spannende (aber dann doch triviale - man kann hier recht frei entscheiden) war hier die HW Verkabelung. Diese ist im yaml dokumentiert. die GPIO Pins stehen im Plan auf der Olimex-Seite.
Auf dem iobroker habe ich ein Javascript um per mqtt die entsprechenden Werte zu liefern:
var fenster1OG=['hm-rpc.3.0000XXXXXXXXXX.1.STATE'/*Fensterkontakt Schlafzimmer:1 STATE*/,
'hm-rpc.0.KEQ00XXXXX.1.STATE'/*Fenster Balko Arbeitszimmer:1 STATE*/,
'hm-rpc.0.KEQ00XXXXX.1.STATE'/*Fenster KiZi:1 STATE*/,
'hm-rpc.0.KEQ00XXXXX.1.STATE'/*Fenster Bad 1OG STATE*/,
'hm-rpc.0.MEQ02XXXXX.1.STATE'/*Fenster Fenster AZ STATE*/];
var fenster2OG=['hm-rpc.0.JEQ0XXXXXX.1.STATE'/*Fenster Dach Nord:1 STATE*/,
'hm-rpc.0.KEQ00XXXXX.1.STATE'/*Fenster Küche STATE*/,
'hm-rpc.0.KEQ00XXXXX.1.STATE'/*Fenster Gaube STATE*/,
'hm-rpc.0.KEQ00XXXXX.1.STATE'/*Fenster Fenster West:1 STATE*/,
'hm-rpc.0.KEQ01XXXXX.1.STATE'/*Fenster Badewanne:1 STATE*/,
'hm-rpc.0.KEQ00XXXXX.1.STATE'/*Fenster Bad 2OG:1 STATE*/];
var presence=['javascript.1.presence_black'/*presence black*/,'javascript.1.presence_white'/*javascript 1 presence white*/]; //u.a. aus den Werten des BLE Scanners ermittler, aber noch aus einem zweiten Scanner und mit einer Hysterese
on({id:'hm-rega.0.XXX'/*Licht 1OG*/, change: "ne"}, function(obj) { //Variable fürs Licht wird bei mir in der CCU gepflegt.
var output;
var input=obj.state.val;
if (input) {
output="An";
} else {
output="Aus";
};
setState('mqtt.0.bt_eingang.display.line_1OG_licht'/*bt eingang/display/line 1OG licht*/,output);
redraw_display();
});
on({id:'hm-rega.0.1XXX'/*Licht2OG*/, change: "ne"}, function(obj) {
var output;
var input=obj.state.val;
if (input) {
output="An";
} else {
output="Aus";
};
setState('mqtt.0.bt_eingang.display.line_2OG_licht'/*bt eingang/display/line 1OG licht*/,output);
redraw_display();
});
on({id:presence, change: "ne"}, function(obj) {
var output="";
if (getState("javascript.1.presence_black").val){
output = output +"Schwarz "; //Hier kann man die Namen der Besitzer eintragen
};
if (getState("javascript.1.presence_white").val) {
output = output + "Weiss ";
};
setState('mqtt.0.bt_eingang.display.presence_string'/*bt eingang/display/presence string*/,output);
redraw_display();
});
on({id:fenster1OG, change: "ne"}, function(obj) {
var output;
var input=obj.state.val;
var open_1OG=0;
var gekippt_1OG=0;
var closed_1OG=0;
for (var i = 0; i < fenster1OG.length; i++) {
var ws = getState(fenster1OG[i]).val;
if (fenster1OG[i]=="hm-rpc.3.0000DXXXXXXX.1.STATE") { //Fensterkontakt mit nur zwei Zuständen
if (ws==0) {
closed_1OG++;
} else if (ws==1) {
open_1OG++;
};
} else { //Normalerweise habe ich Griffsensoren mit 3 Zuständen
if (ws==0) {
closed_1OG++;
} else if (ws==1) {
gekippt_1OG++;
} else if (ws==2) {
open_1OG++;
}
};
};
output = windowstring(open_1OG,gekippt_1OG,closed_1OG);
setState('mqtt.0.bt_eingang.display.line_1OG_fenster'/*bt eingang/display/line 1OG fenster*/,output);
redraw_display();
});
on({id:fenster2OG, change: "ne"}, function(obj) {
var output;
var input=obj.state.val;
var open_2OG=0;
var gekippt_2OG=0;
var closed_2OG=0;
for (var i = 0; i < fenster2OG.length; i++) {
var ws = getState(fenster2OG[i]).val;
if (fenster2OG[i]=="hm-rpc.3.000XXXXXX1.STATE") {
if (ws==0) {
closed_2OG++;
} else if (ws==1) {
open_2OG++;
};
} else {
if (ws==0) {
closed_2OG++;
} else if (ws==1) {
gekippt_2OG++;
} else if (ws==2) {
open_2OG++;
}
};
};
output = windowstring(open_2OG,gekippt_2OG,closed_2OG);
setState('mqtt.0.bt_eingang.display.line_2OG_fenster'/*bt eingang/display/line 1OG fenster*/,output);
redraw_display();
});
on({id:'netatmo.0.XXXX.XXX.Temperature.Temperature'/*Temperature*/, change: "ne"}, function(obj) {
setState('mqtt.0.bt_eingang.display.temp_out'/*bt eingang/display/temp out*/,obj.state.val);
}); //Aussentemperatur. Änderung macht kein Display-Refresh, da das e-ink ca. 2-3 Sekunden beim aktualisieren flackert. Wird bei der nächsten Änderung oder nach 3600s wie im esphome-Skript aktualisiert.
on({id:"daswetter.0.NextHours.Location_1.Day_1.in1hours.symbol_value", change:"ne"}, function(obj){
setState('mqtt.0.bt_eingang.display.headline'/*bt eingang/display/headline*/,obj.state.val);
redraw_display();
}); //Forecast für die nächste Stunde.
function redraw_display() {
setState('mqtt.0.bt_eingang.display.refresh'/*bt eingang/display/refresh*/,"ON");
setStateDelayed('mqtt.0.bt_eingang.display.refresh', "OFF", 1000);
}; //mit "ON" wird das Display aktualisiert.
function windowstring (w_open, w_kipp, w_close){
var output;
if (w_open==0 && w_kipp==0) {
output ="Zu";
} else {
output = "O:"+ w_open +" K:"+ w_kipp;
};
return output;
}
//Das Erdgeschoß ist noch im Umbau, deswegen noch nicht im Skript enthalten
Das ganze sieht dann so aus:
Aktuell habe ich nur noch das Problem, dass ich kein OTA Update auf dem ESP32 machen kann, da das abbricht. Per USB lässt er sich aber problemlos flashen.
In Summe hat die Hardware ca. 70 EUR gekostet (30 EUR für das ESP Board und 37 EUR für das Display mit Versand)
Viel Spass beim nachmachen, es war einfacher als befürchtet:-)
Alexander