This examples is most useful for newbies like me who have experience with Arduino sketches and want to integrate their Arduino automation with 433 switches into OpenHAB.
Let’s face it this will not the only/best road to Rome, other solutions like 1technophile/OpenMQTTGateway will cover perhaps this better. You can also use the RPi as 433-device over an Arduino (or Wemos). In a way easier because you do not require a MQTT-broker (the MQTT-broker setup is not part of this example). The majority of the lines in these sketches are borrowed from others in other words LEGO (C)-style programming (cut, paste, trial and redo).
The most important part are the following routines:
-
getStringPartByNr: to split the topic into smaller pieces to determine the model/brand/type and ID-nummer of the switch (and use in the callback rourine).
-
callback: which includes the different actions for each model/switch. As you can see the sketch is using two different models each model can require their own library, the library for the action switch: flamingo.h is included but can possible already replaced with an official library. If you have other switches you should already know which library you should use.
For your conviniency How to setup these 433/MQTT items in OpenHAB?
Switch Switch7 “Red Lamp” (gLight)
{ mqtt=“<[broker:433/action/7/:state:default], >[broker:433/action/7/:command:*:default]” }Switch Switch9 “Garden Lamp” (gLight)
{ mqtt=“<[broker:433/flamingo/2/:state:default], >[broker:433/flamingo/2/:command:*:default]” }
Missing is the icon “light” and most important here is the last “/” in the topics, otherwise routine getStringPartByNr will not work correctly!!
The Arduino Sketch (requires Arduino UNO + W5100 + 433-transmitter): (I have also adapted this sketch for the Wemos D1 R2 not published, but better to use earlier mention total solution with OTA and config file).
/*
Starting Skectch from: PubSubClient
Splitting topic based upoin: https://arduino.stackexchange.com/questions/1013/how-do-i-split-an-incoming-string
BTW make sure your topic ends with "/"
The following topics can be used in this sketch:
* 433/action/x/ //x value must be in the range 0 to 7
* 433/flamingo/x/ //x value can be ...? please experiment 1 and 2 works with me
433 can be replaced by any onther string, action and flamingo are mandatory
*/
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <Dns.h>
#include <Dhcp.h>
/************************* Ethernet Client Setup *****************************/
// Update these with values suitable for your network.
byte mac[] = {0xDC, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
//Uncomment the following, and set to a valid ip if you don't have dhcp available.
// IPAddress iotIP (192, 168, y, yyy);
//Uncomment the following, and set to your preference if you don't have automatic dns.
//IPAddress dnsIP (8, 8, 8, 8);
//If you uncommented either of the above lines, make sure to change "Ethernet.begin(mac)" to "Ethernet.begin(mac, iotIP)" or "Ethernet.begin(mac, iotIP, dnsIP)"
/*************************** MQTT Setup **************************************/
#define MQTT_SERVER "192.168.x.xxx"
#define MQTT_SERVER_UID "openhabian"
#define MQTT_SERVER_PWD "MyotherSecretPassword"
#define MQTT_SERVERPORT 1883
/*************************** Library Setup **************************************/
// library, variables for Action/Flaminco Switches)
// #define rfPin D7 // uses digital 7 on wemos (the D is important)
#define rfPin 7 // uses digital 7 on Arduino Uno
// const int rfPin = 13; // Pin Digital D7 on Wemos D1 R2
#include "flamingo.h" // library in seperate tab for Action switch (self-learning)
// for Flamingo SF-501PWD (among others)
#include <NewRemoteTransmitter.h> //library can be found on https://bitbucket.org/fuzzillogic/433mhzforarduino/wiki/Home
NewRemoteTransmitter transmitter(14727168, rfPin, 260, 3); //values are transmittercode, pin, miliseconds, repeat
/*************************** Routines **************************************/
void callback(char* topic, byte* payload, unsigned int length) {
int deviceSwitchNr;
String model = getStringPartByNr(topic, '/', 1); // the first part is model
String device = getStringPartByNr(topic, '/', 2); // the second part is device
int deviceNr = device.toInt(); // make from the second part an integer
payload[length] = '\0'; // set a proper EOF to payload
String deviceSwitch = String((char*)payload); // set payload to a string
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
Serial.println(String((char*)payload));
if ( deviceSwitch == "OFF") {
deviceSwitchNr = 1;
} else {
deviceSwitchNr = 0;
}
if ( model == "action" ) {
Flamingo_Send(deviceNr, deviceSwitchNr);
} else if ( model == "flamingo" ) {
transmitter.sendUnit(deviceNr, !deviceSwitchNr); // in this on/off is reversed!
} else {
Serial.println("there is something wrong");
}
}
EthernetClient ethClient;
PubSubClient client(MQTT_SERVER, MQTT_SERVERPORT, callback, ethClient);
void setup()
{
// Ethernet.begin(mac, iotIP); // with IP inside aketch
Ethernet.begin(mac); // with IP based upon DSN-server
// Note - the default maximum packet size is 128 bytes. If the
// combined length of clientId, username and password exceed this,
// you will need to increase the value of MQTT_MAX_PACKET_SIZE in
// PubSubClient.h
if (client.connect(MQTT_SERVER, MQTT_SERVER_UID, MQTT_SERVER_PWD)) {
//client.publish("Topic","hello world");
client.subscribe("433/#");
}
Serial.begin(115200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("Starting.....");
}
void loop()
{
client.loop();
}
String getStringPartByNr(String data, char separator, int index)
{
// spliting a string and return the part nr index
// split by separator
int stringData = 0; //variable to count data part nr
String dataPart = ""; //variable to hole the return text
for(int i = 0; i<data.length()-1; i++) { //Walk through the text one letter at a time
if(data[i]==separator) {
//Count the number of times separator character appears in the text
stringData++;
}else if(stringData==index) {
//get the text when separator is the rignt one
dataPart.concat(data[i]);
}else if(stringData>index) {
//return text and stop if the next separator appears - to save CPU-time
return dataPart;
break;
}
}
//return text if this is the last part
return dataPart;
}
The flamingo.h library:
/*********************************************************************************************************
* Based upon collective works by an unknown author, adapted for Cayenne (or Blynck) by Wouter-Jan *
* Info Flamingo: http://forum.arduino.cc/index.php?topic=201771.0 *
* Info 433: a self-learning 433 libary in wording: https://forum.fhem.de/index.php/topic,36399.60.html *
* *******************************************************************************************************
********************************************************************************
** Flamingo_send **
** **
** Flamingo device commands (on/off)hard coded (not deciphered yet) **
** code is 28 byte long. To transfer it in 32 bit code 4 *0 **
** is added to the left. For programming reason hex code representation **
** of device code is used. E.g. Remote 0,C,On: **
** code 28 bits: 0001100110111111110100100110 **
** code 32 bits: 00011001101111111101001001100000 **
** Hex: 19BFD260 **
** **
** "Sync" 1 pulse High, 15 pulse low **
** "1" 1 pulse High, 3 pulse low **
** "0" 3 pulse High, 1 pulse low **
** "end" N/A **
** **
** For internal ref: Unit 0 = white remote , unit 1 = black remote **
** **
*******************************************************************************/
// Compiler only coding
#define FUNITS 12 /* Amount of units supported */
#define FCMDN 2 /* Amount of CMD 0 = On, 1 = Off */
// int rfPin = D7; /* with ethernet shield D4 = SS (for SD card) (now in main sketch)*/
// define device codes:
uint32_t fdev[FUNITS][FCMDN] = {0xD9762A10, 0xDAA47850, /* Remote 0 */
0xDBDA22E0, 0xDBA27220, /* Remote 1 */
0x19BFD260, 0x195EEAA0, /* Remote 2 */
0x984CC650, 0x9A8C1050, /* Remote 3 */
0xDBFFFE90, 0xD91CEF10, /* Remote 4 */
0xDBC52FA0, 0xD9E35160, /* Remote 5 */
0x19B0FE60, 0x19682B20, /* Remote 6 */
0x9924E7D0, 0x9BA928D0, /* Remote 7 */
0x25B25B60, 0x24DC2060, /* Remote 8 (not tested) */
0x2717B510, 0x275BADD0, /* Remote 9 (not tested) */
0xE56BF910, 0xE4D49F50, /* Remote 10 (not tested) */
0x65F1C2A0, 0x65B67B60 /* Remote 11 (not tested) */
};
// Define Flamingo_send variables / constants
int fpulse = 300; /* Pulse witdh in microseconds */
int fretrans = 5; /* Code retransmission */
uint32_t fsendbuff;
uint32_t fdatabit;
uint32_t fdatamask = 0x80000000;
void Flamingo_Send(int funitc, int fcmd)
{
// Test if used codes are valid
if ((funitc < 0) || (funitc > 11)) { // check if unit code between 0-11 (Remote 0 to 11)
Serial.print("Unit error: ");
Serial.println(funitc);
return;
}
if ((fcmd < 0) || (fcmd > 1)) { // check if command = 0 (off) or 1 (on)
Serial.print("Command error: ");
Serial.println(fcmd);
return;
}
//End test used codes
Serial.println("");
Serial.println("Send Flamingo command: ");
Serial.print("Flamingo Unit = :");
Serial.println(funitc);
Serial.print("command = :");
Serial.println(fcmd);
// Send Command
for (int nRepeat = 0; nRepeat <= fretrans; nRepeat++) {
fsendbuff = fdev[funitc][fcmd];
// send SYNC 1P High, 15P low
Serial.println("Send sync");
digitalWrite(rfPin, HIGH);
delayMicroseconds(fpulse * 1);
digitalWrite(rfPin, LOW);
delayMicroseconds(fpulse * 15);
// end send SYNC
// Send command
for (int i = 0; i < 28; i++) // Flamingo command is only 28 bits */
{
// read data bit
fdatabit = fsendbuff & fdatamask; // Get most left bit
fsendbuff = (fsendbuff << 1); // Shift left
if (fdatabit != fdatamask)
{ // Write 0
digitalWrite(rfPin, HIGH);
delayMicroseconds(fpulse * 3);
digitalWrite(rfPin, LOW);
delayMicroseconds(fpulse * 1);
}
else
{ // Write 1
digitalWrite(rfPin, HIGH);
delayMicroseconds(fpulse * 1);
digitalWrite(rfPin, LOW);
delayMicroseconds(fpulse * 3);
}
}
}
//Serial.println("send code = :");
//Serial.println(fsendbuff);
Serial.println(rfPin);
}