Somfy-Sender selbst domotisieren

Hallo zusammen, ein kleines Tutorial zur Erstellung eines Somfy-Befehlssenders.

Funktionsweise:

Dieses Tutorial ermöglicht es Ihnen, einen 433,42-MHz-Sender zu erstellen, der über WLAN mit dem MQTT-Broker von Gladys verbunden ist, und Tasten zur Steuerung von Rollläden oder ähnlichen Systemen.

Sie können damit Markisen, Rollläden oder andere Systeme steuern, die nach dem Somfy-Steuerungsprinzip funktionieren.

Voraussetzungen

Sie benötigen:

  • ein Lötkolben mit Lötzinn

Anschluss

Der schwierigste Schritt ist das Entfernen des Resonators am Sender, um seinen Ersatz zu löten.

Die blaue LED wird bei jedem Codeversand zwischen dem ESP8266 und dem Sender blinken. Kleine Überprüfung, um sicherzustellen, dass alles funktioniert!

Software-Seite:

Der Treiber für ESP8266-Kopien auf AliExpress kann hier gefunden werden:

Folgen Sie dem Installations-Tutorial.

In Arduino wählen Sie den COM-Port, der Ihrem kleinen Biest entspricht:


Wählen Sie Ihre Karte (Für Kopien von ESP8266-Karten verwende ich diese Kartenreferenz:

wemos

Programmierung

Damit die Gladys-Tasten die vom Sender erwarteten Werte senden können, müssen Sie mehrere MQTT-Fake-Geräte erstellen.

In der MQTT-Integration erstellen Sie 2 „Fake-Geräte“:

  • Steuerung des Rollladens mit seinen 3 Tasten, die die Werte -1, 0 und 1 senden.
  • Ein Dimmerschalter, der von 2 bis 6 inklusive aktiviert wird, um zu programmieren und die Codeschnittstelle zwischen der Rollladentaste und Ihrem Modul zu erstellen.
    In Lien1 im Code angegeben

Sie können ein weiteres Fake-Textgerät erstellen, um in Gladys die Rückmeldung der vom Sender übernommenen Steuerung zu sehen. Das ist im Code vorgesehen, andernfalls lassen Sie es weg.
In Lien2 im Code angegeben



Rollladenstatus
Dimmer
Text

Stellen Sie sicher, dass Sie die Topic-Adressen abrufen, die Sie im Code für den ESP8266 angeben müssen.

Code:

Er enthält wahrscheinlich grobe Fehler, aber ich habe es geschafft, ihn mit meinen geringen Codierkenntnissen zum Laufen zu bringen. Er ist also sehr verbesserungsfähig .. :pray:

Ich bin nicht der Schöpfer des Codes, ich beanspruche daher auch nicht die Verdienste. Ich habe ihn nur angepasst, damit er Zahlenwerte statt Buchstaben akzeptiert.

2 = Down
3 = Stop
4 = Up
5 = Prog
6 =

Die 6 ist absichtlich leer gelassen, um die Programmierung mit dem Originalbefehl durchzuführen.

Wenn Sie mehrere Fernbedienungen erstellen möchten oder wenn Sie nach einer Änderung neu registrieren müssen, denken Sie daran, diesen Wert zu inkrementieren, wie im Beispiel für jeden der Sender angegeben: #define REMOTE 0x122000

/* Dieses Skript ermöglicht es Ihnen, eine Somfy RTS- oder Simu HZ-Fernbedienung zu emulieren.
   
   Dies ist ein Fork des ursprünglichen Skripts, geschrieben von Nickduino (https://github.com/Nickduino)
    
   Wenn Sie mehr über das Somfy RTS-Protokoll erfahren möchten, besuchen Sie https://pushstack.wordpress.com/somfy-rts-protocol/
   
   Der Rollcode wird im EEPROM gespeichert, sodass Sie den D1 Mini mit Strom versorgen können.
   
   Einfachste Methode, um es für Sie funktionieren zu lassen:
    - Wählen Sie eine Fernbedienungsnummer
    - Wählen Sie einen Startpunkt für den Rollcode. Jede unsigned int funktioniert, 1 ist ein guter Start
    - Laden Sie das Skript hoch
    - Drücken Sie lange den Programmierknopf IHRER ECHTEN FERNBEDEINUNG, bis Ihr Rollladen leicht auf und ab geht
    - Senden Sie 'p' an das serielle Terminal oder über 'MQTT'
   Um einen Gruppenbefehl zu machen, wiederholen Sie einfach die letzten beiden Schritte mit einem anderen Rollladen (einer nach dem anderen)
  
   Dann:
    - u wird es nach oben gehen lassen
    - s wird es stoppen
    - d wird es nach unten gehen lassen
    - p setzt den Programmiermodus
    - Sie können auch eine HEX-Zahl direkt für jeden seltsamen Befehl senden, den Sie (0x9 für den Sonnensensor zum Beispiel)
*/

#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <AsyncElegantOTA.h>

WiFiClient espClient;
PubSubClient client(espClient);

String header;
const char* ssid = "xx";   // <-- Geben Sie Ihr WLAN-SSID ein
const char* password = "xx";  // <-- Geben Sie Ihr WLAN-Passwort ein

const char* mqtt_server = "xx";  // <-- Geben Sie die IP Ihres MQTT-Servers ein
const unsigned int mqtt_port = 1883; 
const char* mqtt_user =   "xx"; 
const char* mqtt_password =   "xx"; // <-- Geben Sie das Passwort Ihres MQTT-Servers ein
String clientId = "Awning";

// MQTT-Topic-Parameter
const char* topic = "lien1"; // <-- Das Topic des Variators mit Code
const char* topic2 = "lien2"; // <-- Das Rückmeldungstext-Topic
 
#define SYMBOL 640
#define UP 0x2
#define STOP 0x1
#define DOWN 0x4
#define PROG 0x8
#define EEPROM_ADDRESS 0
#define REMOTE 0x121000    //<-- Ändern Sie dies in eine eindeutige Nummer, wenn Sie mehr als eine Fernbedienung haben (0x121305, 0x121306, 0x121307, ...)

AsyncWebServer server(80);

char demand = '6'; // w = wartend

const int transmitPin = D1;

unsigned long rollingCode = 1;

byte frame[7];
byte checksum;



void BuildFrame(byte *frame, byte button) {
  unsigned int code;
  EEPROM.get(EEPROM_ADDRESS, code);
  frame[0] = 0xA7; // Verschlüsselungsschlüssel. Spielt nicht wirklich eine Rolle
  frame[1] = button << 4;  // Welche Taste haben Sie gedrückt? Die 4 LSB werden die Prüfsumme sein
  frame[2] = code >> 8;    // Rolling Code (Big Endian)
  frame[3] = code;         // Rolling Code
  frame[4] = REMOTE >> 16; // Fernbedienungsadresse
  frame[5] = REMOTE >>  8; // Fernbedienungsadresse
  frame[6] = REMOTE;       // Fernbedienungsadresse

  Serial.print("Frame         : ");
  for(byte i = 0; i < 7; i++) {
    if(frame[i] >> 4 == 0) { // Zeigt führende Nullen an, falls das höchstwertige
      Serial.print("0");     // Nibble eine 0 ist.
    }
    Serial.print(frame[i],HEX); Serial.print(" ");
  }
  
// Berechnung der Prüfsumme: ein XOR aller Nibbles
  checksum = 0;
  for(byte i = 0; i < 7; i++) {
    checksum = checksum ^ frame[i] ^ (frame[i] >> 4);
  }
  checksum &= 0b1111; // Wir behalten nur die letzten 4 Bits


// Integration der Prüfsumme
  frame[1] |= checksum; //  Wenn ein XOR aller Nibbles gleich 0 ist, wird die Prüfsumme von den Jalousien
                        // als in Ordnung betrachtet.

  Serial.println(""); Serial.print("Mit Prüfsumme : ");
  for(byte i = 0; i < 7; i++) {
    if(frame[i] >> 4 == 0) {
      Serial.print("0");
    }
    Serial.print(frame[i],HEX); Serial.print(" ");
  }

  
// Verschleierung: ein XOR aller Bytes
  for(byte i = 1; i < 7; i++) {
    frame[i] ^= frame[i-1];
  }

  Serial.println(""); Serial.print("Verschleiert    : ");
  for(byte i = 0; i < 7; i++) {
    if(frame[i] >> 4 == 0) {
      Serial.print("0");
    }
    Serial.print(frame[i],HEX); Serial.print(" ");
  }
  Serial.println("");
  Serial.print("Rolling Code  : "); Serial.println(code);
  EEPROM.put(EEPROM_ADDRESS, code + 1); //  Wir speichern den Wert des Rolling Codes im
                                        // EEPROM. Es sollte bis zu 2 Adressen belegen, aber die
                                        // Arduino-Funktion kümmert sich darum.
 EEPROM.commit();                                       
}



void SendCommand(byte *frame, byte sync) {
  if(sync == 2) { // Nur mit dem ersten Frame.
  // Aufweckimpuls & Stille
    digitalWrite(transmitPin, HIGH);
    delayMicroseconds(9415);
    digitalWrite(transmitPin, LOW);
    delayMicroseconds(89565);
  }

// Hardware-Synchronisation: zwei Synchronisationen für den ersten Frame, sieben für die folgenden.
  for (int i = 0; i < sync; i++) {
    digitalWrite(transmitPin, HIGH);
    delayMicroseconds(4*SYMBOL);
    digitalWrite(transmitPin, LOW);
    delayMicroseconds(4*SYMBOL);
  }

// Software-Synchronisation
  digitalWrite(transmitPin, HIGH);
  delayMicroseconds(4550);
  digitalWrite(transmitPin, LOW);
  delayMicroseconds(SYMBOL);
  
  
// Daten: Bits werden einzeln gesendet, beginnend mit dem MSB.
  for(byte i = 0; i < 56; i++) {
    if(((frame[i/8] >> (7 - (i%8))) & 1) == 1) {
      digitalWrite(transmitPin, LOW);
      delayMicroseconds(SYMBOL);
      digitalWrite(transmitPin, HIGH);
      delayMicroseconds(SYMBOL);
    }
    else {
      digitalWrite(transmitPin, HIGH);
      delayMicroseconds(SYMBOL);
      digitalWrite(transmitPin, LOW);
      delayMicroseconds(SYMBOL);
    }
  }
  
  digitalWrite(transmitPin, LOW);
  delayMicroseconds(30415); // Zwischenrahmen-Stille
}




void callback(char* topic, byte* payload, unsigned int length) {
    if (strcmp(topic,"lien1") == 0) {
      char demand_str[length + 1];
      strncpy (demand_str, (char*)payload, length);
      demand_str[length] = '\0';
      Serial.println(demand_str);
      
      // u = hoch, d = runter, s = stop, p = programm, w = warten
      
      if (strcmp(demand_str,"4") == 0) {
        demand = '4';
      } else if (strcmp(demand_str,"2") == 0) {
        demand = '2';
      } else if (strcmp(demand_str,"3") == 0) {
        demand = '3';
      } else if (strcmp(demand_str,"5") == 0) {
        demand = '5';
      } else {
        demand = '6';
      }
      Serial.println(demand_str);
      Serial.println(demand);
    }
}

void setup() {
  Serial.begin(115200);
  Serial.println(" ");
  Serial.println("Starting Somfy");
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  WiFi.hostname("Box-Somfy");
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  Serial.println(WiFi.localIP());

  pinMode(transmitPin, OUTPUT); // Pin D1 auf dem Wemos D1 mini
  digitalWrite(transmitPin, LOW);

  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
  request->send(200, "text/plain", "Hi! I am a Wemos D1 mini.");
  });

  AsyncElegantOTA.begin(&server);    // Starte ElegantOTA
  server.begin();


  EEPROM.begin(4);
  EEPROM.get(EEPROM_ADDRESS, rollingCode);

  Serial.println(" ");
  Serial.print("Simulierte Fernbedienungsnummer : "); 
  Serial.println(REMOTE, HEX);
  Serial.print("Aktueller Rolling Code    : "); 
  Serial.println(rollingCode);
}

void reconnect() {
  // Schleife zum Verbinden mit dem MQTT-Broker
  while (!client.connected()) {
    Serial.println("Attempting MQTT connection...");
    if (client.connect("WemosClient", mqtt_user, mqtt_password)) {
      Serial.println("Connected to MQTT");
      // Abonnement des MQTT-Topics
      client.subscribe(topic);
    } else {
      Serial.print("Failed, rc=");
      Serial.print(client.state());
      Serial.println(" Retrying in 5 seconds...");
      delay(5000);
    }
  }
}

void loop() {
  AsyncElegantOTA.loop();

// Überprüfung der Verbindung zum MQTT-Broker
  if (!client.connected()) {
    reconnect();
  }
  // Aktualisierung des MQTT-Clients
  client.loop();

  if (demand == '4' || demand == '2' || demand == '3' || demand == '5') {

//    char serie = (char)Serial.read();
    char serie = (char)demand;
    if(serie == '4') {
      demand = '4';
      Serial.println("up"); // Somfy ist schließlich ein französisches Unternehmen.
      BuildFrame(frame, UP);

      client.publish(topic2, "up");
      delay(50);
      client.subscribe(topic2);
      Serial.println("moving up");
    }
    else if(serie == '2') {
      demand = '2';
      Serial.println("down");
      BuildFrame(frame, DOWN);
      client.publish(topic2, "down");
      delay(50);
      client.subscribe(topic2);
      Serial.println("moving down");
    }
    else if(serie == '5') {
      demand = '5';
      Serial.println("prog");
      BuildFrame(frame, PROG);
      client.publish(topic2, "prog");
      delay(50);
      client.subscribe(topic2);
      Serial.println("prog mode");
    }
    else if(serie == '3') {
      demand = '3';
      Serial.println("stop");
      BuildFrame(frame, STOP);
      client.publish(topic2, "stop");
      delay(50);
      client.subscribe(topic2);
      Serial.println("stop");
    }
    
    demand = '6';

    Serial.println("");
    SendCommand(frame, 2);
    for(int i = 0; i<2; i++) {
      SendCommand(frame, 7);
    }
  }
}

Denken Sie daran, diese Werte entsprechend Ihrer eigenen Installation zu ändern:
• const char* ssid = « Ihr SSID-Netzwerkname »;
• const char* password = « Ihr WLAN-Code »;
• #define MQTT_BROKER « Broker-IP-Adresse »
• #define MQTT_BROKER_PORT 1883
• #define MQTT_USERNAME « MQTT-Broker-Benutzername »
• #define MQTT_KEY « Broker-Passwort »

Wenn Sie diesen Code für mehrere Module mit demselben MQTT-Broker verwenden, denken Sie daran, diesen Wert im Abschnitt « void reconnect » zu ändern:
if (client.connect(« WemosClient2 », mqtt_user, mqtt_password)) {

Gladys-Szenen:

Schließlich, um mit dem neuen Gladys-Alarmsystem zu funktionieren, müssen Sie 3 Szenen für die Rollladensteuerung auf Basis dieser erstellen:

Rollladen herunter: -1 → 2



Gleiches für Stop: 0 → 3
Gleiches für Hoch: 1 → 4

Registrierung des neuen Moduls am Rollladen.

Letzter Schritt, den Rollladen in den Modus zur Registrierung einer neuen Fernbedienung versetzen. Sie sollten auf Ihrer Fernbedienung einen Programmierknopf haben, den Sie einige Sekunden lang drücken müssen. Der Rollladen sollte sich leicht auf und ab bewegen, um dies zu bestätigen.


In Gladys, stellen Sie den Dimmer auf 5. Der Rollladen sollte reagieren und die Bewegung wiederholen.

Wenn ja, dann ist es erledigt :+1:

Wenn nicht, versuchen Sie es erneut, indem Sie den Dimmer auf 6 und dann auf 5 umschalten. Es kann vorkommen, dass Sie den Code ändern müssen, damit der Rollladen dies als neue Fernbedienung interpretiert.

Der Rollladen verlässt den Fernbedienungsregistrierungsmodus von selbst.

Viel Erfolg.
Tiboys

Super Tutorial, auch wenn ich nicht die Schweißkenntnisse und so habe :frowning:

Ich werde in einigen Monaten einen Somfy installieren und es ist cool zu wissen, dass man ihn an Gladys anschließen kann :slight_smile:

Danke

Danke.
Meine Fähigkeiten stammen aus der Schule :face_savoring_food:

Kleine Aktualisierung, die Bibliothek AsyncElegantOTA ist veraltet. Zum Installieren muss man die src-Dateien von diesem Git-Repo herunterladen: GitHub - ayushsharma82/AsyncElegantOTA: Deprecated: Perform OTAs for ESP8266 / ESP32 Elegantly! Uses AsyncWebServer · GitHub und sie in dein Sketch legen, dann diese Zeile ändern:

#include <AsyncElegantOTA.h>

zu:

#include "AsyncElegantOTA.h"

Das Gleiche im AsyncElegantOTA.cpp-File
Man muss auch einige andere Abhängigkeiten installieren, den #error in Zeile 4 von AsyncElegantOTA.h entfernen
Am besten wäre es, zu schauen, ob der Code aktualisiert wurde @tiboys, hast du diesen Code gefunden?
Aber es ist nicht ganz klar, wie mache ich das, wenn ich zwei Fernbedienungen verwalten will? Ich werde zwei Topics abonnieren, aber wie unterscheide ich die Nachrichten der Topics und die Fernbedienung?

@jgcb00, ich hatte den Code hier gefunden:

Heißt das, die Bibliothek ist nicht mehr verfügbar?
Die letzte Aktualisierung des Codes ist 3 Jahre her :face_with_diagonal_mouth:
Ich habe die Bibliothek lokal, aber ich weiß nicht, ob man sie auf einen PC übertragen kann.
Ich habe 2 SOMFY-Rolladen zu Hause, daher habe ich 2 verschiedene ESPs aufgebaut.
Ich kenne mich nicht gut genug mit Code aus, um ihn für 2 Rolladen anzupassen. :grimacing:
Es gibt mehrere ähnliche Seiten im Netz:

https://github.com/rstrouse/ESPSomfy-RTS-HA