Eins vorweg, ich bin in Sachen ArduinoIDE und programmieren blutiger Anfänger und bitte jede Art von Kotzcode zu entschuldigen. Weiterhin ist der Code nicht auf meinen Mist gewachsen, ich hab ihn nur angepasst.
Es war das Ziel eine Shelly Duo mit einem Hardware Teil zusteuern.
Ein Rotary Switch Ky-040 (o.ä.), ein Wemos D1 Mini und 5 Kabel werden benötigt. Weiterhin benutze ich den ioBroker mit installierten mqtt Adapter um den Switch zu betreiben, dieser meldet sich unter mqtt.0/dial/button.../encoder. Der Shelly Adapter ist ebenfalls installiert und Blockly Scripte wird benötigt.
Die Quelle meiner Inspiration ist https://github.com/snizzleorg/esp8266-Dimmer
Schaltplan sieht so aus:
Untitled Sketch 2_Steckplatine.png
Wer mit der ArduinoIDE umgehen kann, flasht diesen Code auf den Wemos D1 Mini:
Einzig die Wlan und ioBroker Daten sind die eigenen zu verwenden. Der mqtt Port ist Standard auf 1883 gesetzt und kann im Code auch angepasst werden.
Spoiler anzeigen
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
const char* ssid = "Wlan_SSID";
const char* password = "Wlan_Passwort";
const char* mqtt_server = "IP_des_ioBroker";
const char* mqtt_user = "name";
const char* mqtt_password = "passwort";
const char* topicEncoder = "dial/encoder";
const char* topicButton = "dial/button";
char charPos [5];
#define pinSW D7 // Connected to SW on KY-040
#define pinA D5 // Connected to CLK on KY-040
#define pinB D6 // Connected to DT on KY-040
int encoderPosCount = 0;
int pinALast;
int aVal;
int Button;
int aButton;
boolean bCW;
String strTopic;
String strPayload;
WiFiClient espClient;
PubSubClient client(espClient);
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
WiFi.mode(WIFI_STA);
WiFi.hostname("Dimmer");
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
payload[length] = '\0';
strTopic = String((char*)topic);
if (strTopic == "dial/SetValue")
{
encoderPosCount = atoi((char*)payload);
Serial.println (encoderPosCount);
}
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("arduinoClient", mqtt_user, mqtt_password)) {
Serial.println("connected");
// Once connected, publish an announcement...
client.subscribe("dial/#");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
pinMode (pinA, INPUT);
pinMode (pinB, INPUT);
pinMode (pinSW, INPUT_PULLUP);
/* Read Pin A
Whatever state it's in will reflect the last position
*/
pinALast = digitalRead(pinA);
Serial.begin (115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
if (!(digitalRead(pinSW) == HIGH)) {
// check if pushbutton is pressed
client.publish(topicButton, "ON");
Serial.println(pinSW);
while (!digitalRead(pinSW)) {} // wait til switch is released
delay(200); // debounce
client.publish(topicButton, "OFF");
}
aVal = digitalRead(pinA);
if (aVal != pinALast) { // Means the knob is rotating
// if the knob is rotating, we need to determine direction
// We do that by reading pin B.
if (digitalRead(pinB) != aVal) {
// Means pin A Changed first - We're Rotating Clockwise
encoderPosCount = encoderPosCount + 3;
if (encoderPosCount > 100) {
encoderPosCount = 100;
}
} else {
// Otherwise B changed first and we're moving CCW
encoderPosCount = encoderPosCount - 3;
if (encoderPosCount < 0) {
encoderPosCount = 0;
}
}
Serial.println(encoderPosCount);
dtostrf(encoderPosCount, 3, 1, charPos);
client.publish(topicEncoder, charPos);
}
pinALast = aVal;
client.loop();
}
Alles anzeigen
Nun zum ioBroker, folgendes Blockly Skript importieren und anpassen.
Spoiler anzeigen
on({id: "mqtt.0.dial.button"/*dial/button*/, change: "gt"}, async function (obj) {
var value = obj.state.val;
var oldValue = obj.oldState.val;
getState("shelly.0.SHBDUO-1#D1674C#1.lights.Switch", function (err, state) {
setState("shelly.0.SHBDUO-1#D1674C#1.lights.Switch"/*Switch*/, state ? !state.val : true);
});
});
on({id: 'mqtt.0.dial.encoder', change: "ne"}, async function (obj) {
var value = obj.state.val;
var oldValue = obj.oldState.val;
setState("shelly.0.SHBDUO-1#D1674C#1.lights.brightness"/*Brightness*/, getState("mqtt.0.dial.encoder").val);
});
Alles anzeigen
<xml xmlns="https://developers.google.com/blockly/xml">
<block type="on" id="bbJZUC;KPwR~zgOXkNJV" x="-287" y="12">
<field name="OID">mqtt.0.dial.button</field>
<field name="CONDITION">gt</field>
<field name="ACK_CONDITION"></field>
<statement name="STATEMENT">
<block type="toggle" id="++=VnOE^(^^glr-AnyW=">
<mutation xmlns="http://www.w3.org/1999/xhtml" delay_input="false"></mutation>
<field name="OID">shelly.0.SHBDUO-1#D1674C#1.lights.Switch</field>
<field name="WITH_DELAY">FALSE</field>
</block>
</statement>
<next>
<block type="on_ext" id="~-RmTPfP4tA`/6N5b@PX">
<mutation xmlns="http://www.w3.org/1999/xhtml" items="1"></mutation>
<field name="CONDITION">ne</field>
<field name="ACK_CONDITION"></field>
<value name="OID0">
<shadow type="field_oid" id="vif3zF{E@g_#C|S|D[v(">
<field name="oid">mqtt.0.dial.encoder</field>
</shadow>
</value>
<statement name="STATEMENT">
<block type="control" id="=g#V^tpgYd.ZO4clKCS+">
<mutation xmlns="http://www.w3.org/1999/xhtml" delay_input="false"></mutation>
<field name="OID">shelly.0.SHBDUO-1#D1674C#1.lights.brightness</field>
<field name="WITH_DELAY">FALSE</field>
<value name="VALUE">
<block type="get_value" id="dQVMoF%RZzcV9(YbLh3G">
<field name="ATTR">val</field>
<field name="OID">mqtt.0.dial.encoder</field>
</block>
</value>
</block>
</statement>
</block>
</next>
</block>
</xml>
Alles anzeigen
Das Blockly sieht so aus und kann Ein/Aus schalten und Dimmen, nein warm/kalt kann es nicht, dazu bin ich nicht in der lage das zu programmieren.
So das wars auch schon, publizieren dauert 30 min, erdenken, tüfteln, code suchen dauerte fast 4 Wochen.