Copy philps Hue settings to other RGB device with Domoticz/Mysensor
-
I have been annoyed by the high price of the HUE LED strips, we have a few HUE lamps at home and one led strip and would like more of the LED strips but not the retail price... The led strips are behind different cabinets in the living and we normally pick about the same color for them and we only set them once or twice a day, so I don't care about latency.
So my target was to make a cheap small copy of the HUE led strip with a wireless connection to domoticz that can copy over the colors of a HUE bulb or other LED strip.
Since I want it wireless mysensor seemed the most easy and since I already have a few other mysensor nodes.
To keep it wireless I decided to use a ESP unit and not a normal arduino with radio, just because of the size.I made a small PCB with:
- 3 transistor's BC337 for PWM output to the led strip up to 0.8A per color (~10W/color)
- DB18B20 (to measure temperature and detect overheating)
- 3.3V power supply
- reset button
- header for programming
- jumper for GPIO 0 to set the unit to programming mode
I use a CP2102 programmer to program the ESP unit with arduino IDE
and with a little 12V supply I can hook up any RGB LED strip
I have made 2 arduino scripts to control the LED's, one based on the fastled library and one just writing analog output values for the PWM signal
Only open now is to fade in and out when changing brightness, but the start of that is already in the script
the temperature sensor will detect if the unit overheats and will switch if off for 1 minute, if that happens 5 times the unit will go into deep sleep mode and you need to manually reset the unit
The fast led version I also tested with adafruit neopixels... only the small strips with 8 lixed LEDs flicker but the normal LED strip not so that seems not related to my control but to the LED'sIn the fast led based arduino code for brightness adjustment I just manually set a percentage that matches on first sight
#define FASTLED_ESP8266_RAW_PIN_ORDER #include <FastLED.h> #include <EEPROM.h> #include <SPI.h> #include <DallasTemperature.h> #include <OneWire.h> // Enable debug prints to serial monitor #define MY_DEBUG // Use a bit lower baudrate for serial prints on ESP8266 than default in MyConfig.h #define MY_BAUD_RATE 9600 // Setup gateway #define MY_GATEWAY_ESP8266 #define MY_ESP8266_SSID "MY WIFI" #define MY_ESP8266_PASSWORD "password" #define MY_IP_ADDRESS 192,168,2,151 #define MY_IP_GATEWAY_ADDRESS 192,168,2,254 #define MY_IP_SUBNET_ADDRESS 255,255,255,0 #define MY_PORT 5003 #define MY_GATEWAY_MAX_CLIENTS 2 #define MY_MAC_ADDRESS 0x90, 0xA2, 0xDA, 0x10, 0x1D, 0x91 #include <ESP8266WiFi.h> #include <MySensor.h> #define SKETCH_NAME "RGB_STRIP_TEMPERATURE" #define SKETCH_VERSION "1.0.0" #define NODE_REPEAT false #define NODE_ID 2 //setup timer to get temperature measurement #include <SimpleTimer.h> SimpleTimer timer; //heartbeat timer SimpleTimer timerheartbeat; // define heartbeat variables #define CHILD_ID_HEART 100 int heartbeatcount = 0; MyMessage msgHeart(CHILD_ID_HEART,V_TRIPPED); //RGB test sensor stuff //define RGB pins #define RED_PIN 12 #define GREEN_PIN 13 #define BLUE_PIN 14 int H=0; int S=0; int V=0; int brightnessR = 0; int brightnessG = 0; int brightnessB = 0; int brightnessRold = 0; //prepared for fading in and out of brightness int brightnessGold = 0; //prepared for fading in and out of brightness int brightnessBold = 0; //prepared for fading in and out of brightness int Rcorrection = 100; // color correction for specific leds in % int Gcorrection = 90; // color correction for specific leds in % int Bcorrection = 100; // color correction for specific leds in % #define CHILD_ID_RGB 0 #define ID_RGB_TEXT 38 //IDX of the text unility in domoticz holding the HEU values int off = 0; //intensity when off int actRGBonoff=0; // OnOff flag MyMessage msg(CHILD_ID_RGB,V_CUSTOM); // Led brightness adjusement const int pwmIntervals = 1023; //1023 for ESP units and 255 for arduino // Dallas stuff #define CHILD_ID_TEMP 1 #define ONE_WIRE_BUS 4 // Pin where dallase sensor is connected #define MAX_ATTACHED_DS18B20 2 OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) DallasTemperature sensors(&oneWire); // Pass the oneWire reference to Dallas Temperature. float lastTemperature[MAX_ATTACHED_DS18B20]; int numSensors=0; boolean receivedConfig = false; boolean metric = true; // Initialize temperature message MyMessage msgTemp(CHILD_ID_TEMP,V_TEMP); float overheat=70; //temperature at which the dimmer will shut off to prevent damage #define CHILD_ID_OVERHEAT 200 MyMessage msgOverheat(CHILD_ID_OVERHEAT,V_TRIPPED); int Overheatcounter = 0; void setup() { Serial.begin(9600); Serial.println("Starting setup" ); // Setup locally attached leds pinMode(RED_PIN, OUTPUT); pinMode(GREEN_PIN, OUTPUT); pinMode(BLUE_PIN, OUTPUT); sendSketchInfo(SKETCH_NAME, SKETCH_VERSION); present(CHILD_ID_RGB, S_RGB_LIGHT); present(CHILD_ID_TEMP, S_TEMP); request(CHILD_ID_RGB, V_RGB); present(CHILD_ID_OVERHEAT, S_DOOR); //setup measurement timer interval timer.setInterval(60000, getTemp); // in miliseconds // setup heartbeat timer interval timerheartbeat.setInterval(360000, checkReboot); // 6 minutes in miliseconds present(CHILD_ID_HEART, S_DOOR); // Startup up the OneWire library sensors.begin(); // requestTemperatures() will not block current thread sensors.setWaitForConversion(false); } void presentation() { Serial.println("Presentation:"); // Send the sketch version information to the gateway and Controller sendSketchInfo(SKETCH_NAME, SKETCH_VERSION); // Fetch the number of attached temperature sensors numSensors = sensors.getDeviceCount(); Serial.print("temperature sensors: "); Serial.println(numSensors); // Present all sensors to controller for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) { present(CHILD_ID_TEMP, S_TEMP); } present(CHILD_ID_OVERHEAT, S_DOOR); present(CHILD_ID_RGB, S_RGB_LIGHT); // Present heartbeat signal present(CHILD_ID_HEART, S_DOOR); // Presentation completed Serial.println("Setup completed" ); } // Check if digital input has changed and send in new value void loop() { timer.run(); timerheartbeat.run(); } void checkReboot() { Serial.println("check if heart is still beating"); if (heartbeatcount <= 4 ){ send(msgHeart.set(0)); // present(CHILD_ID, S_RGB_LIGHT); // request(CHILD_ID, V_RGB); send(msg.set(0)); Serial.println("rebooting ESP due to no communication"); ESP.restart(); } else { heartbeatcount = 0; Serial.println("Heartbeat still beating"); Serial.println("Heartbeat counter reset"); Serial.print("Heartbeat count: "); Serial.println(heartbeatcount); send(msgHeart.set(0)); } } void getTemp() { Serial.println("Loop for temperature sensors:"); // Fetch temperatures from Dallas sensors sensors.requestTemperatures(); // query conversion time and sleep until conversion completed int16_t conversionTime = sensors.millisToWaitForConversion(sensors.getResolution()); // sleep() call can be replaced by wait() call if node need to process incoming messages (or if node is repeater) sleep(conversionTime); // Read temperatures and send them to controller for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) { // Fetch and round temperature to one decimal float temperature = static_cast<float>(static_cast<int>((getConfig().isMetric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.; Serial.print("Reading sensor: "); Serial.print(i+1); Serial.print(" with value: "); Serial.println(temperature); // Send in the new temperature send(msgTemp.set(temperature,1)); // Save new temperatures for next compare lastTemperature[i]=temperature; if (temperature>=overheat){ Serial.println("Power off overheat protection" ); send(msgOverheat.set(1)); Overheatcounter = Overheatcounter +1; actRGBonoff=0; analogWrite(RED_PIN, off); analogWrite(GREEN_PIN, off); analogWrite(BLUE_PIN, off); send(msg.set(0)); if (Overheatcounter == 5){ ESP.deepSleep(999999999*999999999U, WAKE_NO_RFCAL); } Serial.println("Sleep 60 seconds to cool down" ); delay(60000); Serial.println("Requestion RGB values" ); send(msg.set(ID_RGB_TEXT)); } if (temperature<=overheat){ send(msgOverheat.set(0)); } } // Serial.println("Rquest RGB settings"); // present(CHILD_ID, S_RGB_LIGHT); // request(CHILD_ID, V_RGB); } String getValue(String data, char separator, int index) { int found = 0; int strIndex[] = {0, -1 }; int maxIndex = data.length()-1; for(int i=0; i<=maxIndex && found<=index; i++){ if(data.charAt(i)==separator || i==maxIndex){ found++; strIndex[0] = strIndex[1]+1; strIndex[1] = (i == maxIndex) ? i+1 : i; } } return found>index ? data.substring(strIndex[0], strIndex[1]) : ""; } void showAnalogRGB( const CRGB& rgb) { //storing previous settings Serial.println("Storing previous settings"); brightnessRold=brightnessR; brightnessGold=brightnessG; brightnessBold=brightnessB; Serial.print("rgb.r "); Serial.println(rgb.r); int brightnessR=(((rgb.r*pwmIntervals)/255)*Rcorrection)/100; Serial.print("brightnessR "); Serial.println(brightnessR); analogWrite(RED_PIN, brightnessR ); Serial.print("rgb.g "); Serial.println(rgb.g); int brightnessG=(((rgb.g*pwmIntervals)/255)*Gcorrection)/100; Serial.print("brightnessG "); Serial.println(brightnessG); analogWrite(GREEN_PIN, brightnessG ); Serial.print("rgb.b "); Serial.println(rgb.b); int brightnessB=(((rgb.b*pwmIntervals)/255)*Bcorrection)/100; Serial.print("brightnessB "); Serial.println(brightnessB); analogWrite(BLUE_PIN, brightnessB ); } void receive(const MyMessage &message) { //check if the message is heartbeat if (message.type==V_LIGHT){ if (message.sensor==CHILD_ID_HEART) { // Read message Serial.print("Incoming change for sensor:"); Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(message.getBool()); send(msgHeart.set(0)); heartbeatcount = heartbeatcount+1; Serial.print("Heartbeat count: "); Serial.println(heartbeatcount); } } if (message.type == V_RGB || message.type == V_DIMMER) { if (actRGBonoff == 1){ Serial.println("RGB message received" ); Serial.println("Sleep before requesting RGB values" ); sleep (2000); Serial.println("Requesting RGB values" ); send(msg.set(ID_RGB_TEXT)); } } if (message.type == V_CUSTOM) { if (actRGBonoff == 1){ String cMessage = message.getString(); Serial.print("cMessage" ); Serial.println(cMessage); int Horg; int H; static uint8_t S; static uint8_t V; Horg=getValue(cMessage, '#', 2).toInt(); H=((Horg*255)/65536); S=getValue(cMessage, '#', 3).toInt(); V=getValue(cMessage, '#', 4).toInt(); showAnalogRGB( CHSV( H, S, V) ); Serial.print("Horg "); Serial.println(Horg); Serial.print("H "); Serial.println(H); Serial.print("S "); Serial.println(S); Serial.print("V "); Serial.println(V); } } if (message.type == V_LIGHT and message.sensor== CHILD_ID_RGB) { if (message.getInt() == 0) { Serial.println("Power off toggle" ); analogWrite(RED_PIN, off); analogWrite(GREEN_PIN, off); analogWrite(BLUE_PIN, off); actRGBonoff=0; } if (message.getInt() == 1) { Serial.println("Power on toggle" ); Serial.println("Sleep before requesting RGB values" ); actRGBonoff=1; sleep (2000); Serial.println("Requesting RGB values" ); send(msg.set(ID_RGB_TEXT)); } } Serial.println(" "); }
analog output write code i used a brightness adjustment trick found on this page
link text#include <EEPROM.h> #include <SPI.h> #include <DallasTemperature.h> #include <OneWire.h> // Enable debug prints to serial monitor #define MY_DEBUG // Use a bit lower baudrate for serial prints on ESP8266 than default in MyConfig.h #define MY_BAUD_RATE 9600 // Setup gateway #define MY_GATEWAY_ESP8266 #define MY_ESP8266_SSID "MY WIFI" #define MY_ESP8266_PASSWORD "password" #define MY_IP_ADDRESS 192,168,2,151 #define MY_IP_GATEWAY_ADDRESS 192,168,2,254 #define MY_IP_SUBNET_ADDRESS 255,255,255,0 #define MY_PORT 5003 #define MY_GATEWAY_MAX_CLIENTS 2 #define MY_MAC_ADDRESS 0x90, 0xA2, 0xDA, 0x10, 0x1D, 0x91 #include <ESP8266WiFi.h> #include <MySensor.h> #define SKETCH_NAME "RGB_STRIP_TEMPERATURE" #define SKETCH_VERSION "1.0.0" #define NODE_REPEAT false #define NODE_ID 2 //setup timer to get temperature measurement #include <SimpleTimer.h> SimpleTimer timer; //heartbeat timer SimpleTimer timerheartbeat; // define heartbeat variables #define CHILD_ID_HEART 100 int heartbeatcount = 0; MyMessage msgHeart(CHILD_ID_HEART,V_TRIPPED); //RGB test sensor stuff //define RGB pins #define RED_PIN 12 #define GREEN_PIN 13 #define BLUE_PIN 14 int brightnessR; int brightnessG; int brightnessB; int brightnessRold = 0; //prepared for fading in and out of brightness int brightnessGold = 0; //prepared for fading in and out of brightness int brightnessBold = 0; //prepared for fading in and out of brightness int Rcorrection = 100; // color correction for specific leds in % int Gcorrection = 100; // color correction for specific leds in % int Bcorrection = 100; // color correction for specific leds in % #define CHILD_ID_RGB 0 #define ID_RGB_TEXT 38 //IDX of the text unility in domoticz holding the HEU values long RGB_values[3] = {0, 0, 0}; int off = 0; //intensity when off String hexstring; //HEX string for RGB value int dimmer; //dimmer value in percentage int actRGBonoff=0; // OnOff flag MyMessage msg(CHILD_ID_RGB,V_CUSTOM); // Led brightness adjusement // The number of Steps between the output being on and off // source from https://diarmuid.ie/blog/pwm-exponential-led-fading-on-arduino-or-other-platforms/ const int pwmIntervals = 1023; const int brightnessmax = 1023; // The R value in the graph equation float R; // Dallas stuff #define CHILD_ID_TEMP 1 #define ONE_WIRE_BUS 4 // Pin where dallase sensor is connected #define MAX_ATTACHED_DS18B20 2 OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) DallasTemperature sensors(&oneWire); // Pass the oneWire reference to Dallas Temperature. float lastTemperature[MAX_ATTACHED_DS18B20]; int numSensors=0; boolean receivedConfig = false; boolean metric = true; // Initialize temperature message MyMessage msgTemp(CHILD_ID_TEMP,V_TEMP); float overheat=70; //temperature at which the dimmer will shut off to prevent damage #define CHILD_ID_OVERHEAT 200 MyMessage msgOverheat(CHILD_ID_OVERHEAT,V_TRIPPED); int Overheatcounter = 0; void setup() { Serial.begin(9600); Serial.println("Starting setup" ); // Setup locally attached leds pinMode(RED_PIN, OUTPUT); pinMode(GREEN_PIN, OUTPUT); pinMode(BLUE_PIN, OUTPUT); sendSketchInfo(SKETCH_NAME, SKETCH_VERSION); present(CHILD_ID_RGB, S_RGB_LIGHT); present(CHILD_ID_TEMP, S_TEMP); request(CHILD_ID_RGB, V_RGB); present(CHILD_ID_OVERHEAT, S_DOOR); // calculatebrightness adjustment R = (pwmIntervals * log10(2))/(log10(brightnessmax)); //setup measurement timer interval timer.setInterval(60000, getTemp); // in miliseconds // setup heartbeat timer interval timerheartbeat.setInterval(360000, checkReboot); // 6 minutes in miliseconds present(CHILD_ID_HEART, S_DOOR); // Startup up the OneWire library sensors.begin(); // requestTemperatures() will not block current thread sensors.setWaitForConversion(false); } void presentation() { Serial.println("Presentation:"); // Send the sketch version information to the gateway and Controller sendSketchInfo(SKETCH_NAME, SKETCH_VERSION); // Fetch the number of attached temperature sensors numSensors = sensors.getDeviceCount(); Serial.print("sensors: "); Serial.println(numSensors); // Present all sensors to controller for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) { present(CHILD_ID_TEMP, S_TEMP); } present(CHILD_ID_OVERHEAT, S_DOOR); present(CHILD_ID_RGB, S_RGB_LIGHT); // Present heartbeat signal Serial.println("Present heartbeat signal"); present(CHILD_ID_HEART, S_DOOR); // Presentation completed Serial.println("Setup completed" ); } // Check if digital input has changed and send in new value void loop() { timer.run(); timerheartbeat.run(); } void checkReboot() { Serial.println("check if heart is still beating"); if (heartbeatcount <= 4 ){ send(msgHeart.set(0)); // present(CHILD_ID, S_RGB_LIGHT); // request(CHILD_ID, V_RGB); send(msg.set(0)); Serial.println("rebooting ESP due to no communication"); ESP.restart(); } else { heartbeatcount = 0; Serial.println("Heartbeat still beating"); Serial.println("Heartbeat counter reset"); Serial.print("Heartbeat count: "); Serial.println(heartbeatcount); send(msgHeart.set(0)); } } void getTemp() { Serial.println("Loop for temperature sensors:"); // Fetch temperatures from Dallas sensors sensors.requestTemperatures(); // query conversion time and sleep until conversion completed int16_t conversionTime = sensors.millisToWaitForConversion(sensors.getResolution()); // sleep() call can be replaced by wait() call if node need to process incoming messages (or if node is repeater) sleep(conversionTime); // Read temperatures and send them to controller for (int i=0; i<numSensors && i<MAX_ATTACHED_DS18B20; i++) { // Fetch and round temperature to one decimal float temperature = static_cast<float>(static_cast<int>((getConfig().isMetric?sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.; Serial.print("Reading sensor: "); Serial.print(i+1); Serial.print(" with value: "); Serial.println(temperature); // Send in the new temperature send(msgTemp.set(temperature,1)); // Save new temperatures for next compare lastTemperature[i]=temperature; if (temperature>=overheat){ Serial.println("Power off overheat protection" ); send(msgOverheat.set(1)); Overheatcounter = Overheatcounter +1; actRGBonoff=0; analogWrite(RED_PIN, off); analogWrite(GREEN_PIN, off); analogWrite(BLUE_PIN, off); send(msg.set(0)); if (Overheatcounter == 5){ ESP.deepSleep(999999999*999999999U, WAKE_NO_RFCAL); } Serial.println("Sleep 60 seconds to cool down" ); delay(60000); Serial.println("Requestion RGB values" ); send(msg.set(ID_RGB_TEXT)); } if (temperature<=overheat){ send(msgOverheat.set(0)); } } // Serial.println("Rquest RGB settings"); // present(CHILD_ID, S_RGB_LIGHT); // request(CHILD_ID, V_RGB); } String getValue(String data, char separator, int index) { int found = 0; int strIndex[] = {0, -1 }; int maxIndex = data.length()-1; for(int i=0; i<=maxIndex && found<=index; i++){ if(data.charAt(i)==separator || i==maxIndex){ found++; strIndex[0] = strIndex[1]+1; strIndex[1] = (i == maxIndex) ? i+1 : i; } } return found>index ? data.substring(strIndex[0], strIndex[1]) : ""; } void receive(const MyMessage &message) { //check if the message is heartbeat if (message.type==V_LIGHT){ if (message.sensor==CHILD_ID_HEART) { // Read message Serial.print("Incoming change for sensor:"); Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(message.getBool()); send(msgHeart.set(0)); heartbeatcount = heartbeatcount+1; Serial.print("Heartbeat count: "); Serial.println(heartbeatcount); } } if (message.type == V_RGB || message.type == V_DIMMER) { if (actRGBonoff == 1){ Serial.println("RGB message received" ); Serial.println("Sleep before requesting RGB values" ); sleep (2000); Serial.println("Requesting RGB values" ); send(msg.set(ID_RGB_TEXT)); } } if (message.type == V_CUSTOM) { //storing previous settings Serial.println("Storing previous settings"); brightnessRold=brightnessR; brightnessGold=brightnessG; brightnessBold=brightnessB; if (actRGBonoff == 1){ String cMessage = message.getString(); Serial.print("cMessage" ); Serial.println(cMessage); hexstring=getValue(cMessage, '#', 2); // split dimmer values dimmer=(getValue(cMessage, '#', 3)).toInt(); Serial.print("Dimmer " ); Serial.println(dimmer); // split RGB values Serial.print("New RGB values " ); Serial.println(hexstring); long number = (long) strtol( &hexstring[0], NULL, 16); Serial.println(number); // separate HEX string in RGB values RGB_values[0] = number >> 16; RGB_values[1] = number >> 8 & 0xFF; RGB_values[2] = number & 0xFF; // RGB value to display as send by the server long r1 = int(RGB_values[0]); long g1 = int(RGB_values[1]); long b1 = int(RGB_values[2]); // calculate RGB value to display long r = int((RGB_values[0] * dimmer/100)); long g = int((RGB_values[1] * dimmer/100)); long b = int((RGB_values[2] * dimmer/100)); // set value of RGB controller int red = ((r*1023)/255); int green = ((g*1023)/255); int blue = ((b*1023)/255); //adjust brightness non linear brightnessR = pow (2, (red / R)) - 1; brightnessG = pow (2, (green / R)) - 1; brightnessB = pow (2, (blue / R)) - 1; int Rpwm=(brightnessR*Rcorrection)/100; int Gpwm=(brightnessG*Gcorrection)/100; int Bpwm=(brightnessB*Bcorrection)/100; Serial.print("r "); Serial.println(r1); Serial.print("r dimmed "); Serial.println(r); Serial.print("r-ESP "); Serial.println(red); Serial.print("g "); Serial.println(g1); Serial.print("g dimmed "); Serial.println(g); Serial.print("g-ESP "); Serial.println(green); Serial.print("b "); Serial.println(b1); Serial.print("b dimmed "); Serial.println(b); Serial.print("b-ESP "); Serial.println(blue); Serial.print("red brightness adjusted "); Serial.println(brightnessR); Serial.print("green brightness adjusted "); Serial.println(brightnessG); Serial.print("blue brightness adjusted "); Serial.println(brightnessB); Serial.print("red PWM output "); Serial.println(Rpwm); Serial.print("green PWM output "); Serial.println(Gpwm); Serial.print("blue PWM output "); Serial.println(Bpwm); // write RGB value to controller analogWrite(RED_PIN, Rpwm); analogWrite(GREEN_PIN, Gpwm); analogWrite(BLUE_PIN, Bpwm); } } if (message.type == V_LIGHT and message.sensor== CHILD_ID_RGB) { if (message.getInt() == 0) { Serial.println("Power off toggle" ); analogWrite(RED_PIN, off); analogWrite(GREEN_PIN, off); analogWrite(BLUE_PIN, off); brightnessRold=0; brightnessGold=0; brightnessBold=0; actRGBonoff=0; } if (message.getInt() == 1) { Serial.println("Power on toggle" ); Serial.println("Sleep before requesting RGB values" ); actRGBonoff=1; sleep (2000); Serial.println("Requesting RGB values" ); send(msg.set(ID_RGB_TEXT)); } } Serial.println(" "); }
-
in domoticz I have 2 lua scripts running for the HUE control, 1 time based and one triggered by the device change
next to that I have 1 watchdog script that switches on ID 100 to the node and the node will reply with an off at that ID so the node can be reset if there is no communication
a user variable has to be creased to store the current HUE settings (String)
a dummy text utility has to be created to store the HSV or RGB and dimmer values for the mysensor node to requestThe device script contains calculations from HSV to RGB and RGB hex, I tried different formats for fowarding the data to the mysensor node and just kept it in the script in case I might need it later for troubleshooting
-- this script reads the setting of 1 HUE RGB device and forwards this to a mysensor RGB dimmer -- one script will do this time based and the second script will do this on a device change, in order to capture changed made from domoticz and through the HUE bridge directly -- HUE stores the values in HSV format where the mysensor node uses RGB values for the RGB LED's so these have to be converted before forwarding -- a user variable has to be creased to store the current HUE settings (String) -- a dummy text utility has to be created to store the HSV or RGB and dimmer values for the mysensor node to request -- additional libraries for lua have to be installed -- how to do this can be found in the help wiki http://www.domoticz.com/wiki/Upload_energy_data_to_PVoutput#Install_socket_library -- or from http://www.domoticz.com/forum/viewtopic.php?f=5&t=1847&p=22638#p22638 -- for json processing I use http://regex.info/code/JSON.lua on a raspberry pi -- on a synology nas dkjson seems to do a better job http://dkolf.de/src/dkjson-lua.fsl/home -- all need to end up in /usr/local/lib/lua/5.2 commandArray = {} -- fixed values base_url = 'http://192.168.2.150/api/fd81c2245c8797cec333e351d01a3' -- hue URL and username domoticz_url = 'http://192.168.2.140:8080' --URL of domoticz server HUE_Strip_ID = 6 -- HUE ID of deviced to be replicated HUE_CURRENT = 'Led_HUE' -- Uservariable (String) to store HUE setting Source_Name = 'HueStrip' -- Name of the HUE device to be copied in Domoticz Target_IDX = 229 -- IDX of target device Target_Name = 'RGB_Led' -- exact device name Target_IDX_TXT=38 -- IDX for HSV values ForwardType = 'HSV' -- HSV or RGB to be forwarded to the mysensor node PRINT_MODE = false -- when true wil print output to log and send notifications if (devicechanged[Source_Name]) then -- optional and (uservariables['HUE_Forward_LAN']==1) if (otherdevices[Source_Name] == 'Off') then -- set copied device to off commandArray[Target_Name] = 'Off' else -- Only load libaries now http = require('socket.http') ltn12 = require('ltn12') json = require('JSON') io = require('io') -- set some local variables device = '' mode = 'GET' params = '' function hueread(device, operation, mode) local t = {} local url = base_url .. device local req_body = operation if PRINT_MODE == true then print(url) print(req_body) end local headers = { ["Content-Type"] = "application/json"; ["Content-Length"] = #req_body; } client, code, headers, status = http.request{url=url, headers=headers, source=ltn12.source.string(req_body), sink = ltn12.sink.table(t), method=mode} if PRINT_MODE == true then print(status) end return t end function processJSON(t) obj, pos, err = json:decode(table.concat(t),1,nil) if PRINT_MODE == true then print(table.concat(t)) print("check for error") end if err then print ("Error for HUE Bridge:", err) else if PRINT_MODE == true then print("no error") end data = '' i=HUE_Strip_ID state=obj.lights[tostring(i)].state dataHUE = data .. state.bri ..'|'.. state.hue ..'|'.. state.sat dataStatus = state.on -- checking if HUE strip is off if state.on==false then if PRINT_MODE == true then if otherdevices[Target_Name] ~= 'Off' then print('HUE LED is off, but RGB LED was on') else print('HUE LED is off, no action') end commandArray[Target_Name] = 'Off' if PRINT_MODE == true then print('Sending off switch command just to be sure') end end else -- checking if HUE strip is on but led strip is off if state.on==true then if otherdevices[Target_Name] == 'Off' then if PRINT_MODE == true then print('Switching RGB led on') end commandArray[Target_Name] = 'On' if PRINT_MODE == true then print('Hue ID checked: ' .. i) print('Status on: On') print('HUE: ' .. dataHUE) print('length of encode '..#dataHUE) end else if PRINT_MODE == true then print('RGB led already on, checking settings') end commandArray[Target_Name] = 'On' if PRINT_MODE == true then print('Sending on switch command just to be sure') end end -- Collecting color data to compare Old_data = tostring(uservariables[HUE_CURRENT]) New_data = tostring(dataHUE) if New_data ~= Old_data then print('HUE data changed') if PRINT_MODE == true then print('New data:' .. New_data) print('Old data:' ..Old_data) print('') end -- convert HUE values to HSV H=((state.hue)/65534) S=((state.sat)/254) V=((state.bri)/254) --convert HUE to domoticz values Hue=tostring(math.floor(H*360)) Sat=tostring(math.floor(S*100)) Bri=tostring(math.floor(V*100)) -- convert HSV to RGB and RGB hex values R, G, B =HSVtoRGB(H, S, V) if R >= 16 then Rhex=num2hex(R) else Rhex='0'.. num2hex(R) end if G >= 16 then Ghex=num2hex(G) else Ghex='0'.. num2hex(G) end if B >= 16 then Bhex=num2hex(B) else Bhex='0'.. num2hex(B) end RGB= R ..'|'.. G ..'|'.. B RGBhex= Rhex ..''.. Ghex ..''.. Bhex if PRINT_MODE == true then -- Reverse calculations of hue values for validation Hr, Sr, Vr =RGBtoHSV(R, G, B) Hrev=round((Hr*65536),0) Srev=round((Sr*256),0) Vrev=round((Vr*256),0) -- print all calculated data print('Hue Hue light: ' .. state.hue) print('Sat Hue light: ' .. state.sat) print('Bright Hue light: ' .. state.bri) print(' ') print('Hue domoticz: ' .. Hue) print('Sat domoticz: ' .. Sat) print('Bri domoticz: ' .. Bri) print(' ') print('H: ' .. H) print('S: ' .. S) print('V: ' .. V) print(' ') print('R: ' .. R) print('G: ' .. G) print('B: ' .. B) print('RGB: ' .. RGB) print(' ') print('Rhex: ' .. Rhex) print('Ghex: ' .. Ghex) print('Bhex: ' .. Bhex) print('RGBhex: ' .. RGBhex) print(' ') print('H reversed: ' .. Hrev) print('S reversed: ' .. Srev) print('V reversed: ' .. Vrev) end -- set LED strip if (ForwardType=='RGB') then -- store RGB as text datanew_TXT=RGBhex..";"..Bri..";" commandArray['UpdateDevice'] = Target_IDX_TXT .. '|0|' .. tostring(datanew_TXT) if PRINT_MODE == true then print('Storing RGB text value:' .. datanew_TXT) end end if (ForwardType=='HSV') then -- store HSV as text datanew_HSV=state.hue..";"..state.sat..";"..state.bri..";" commandArray['UpdateDevice'] = Target_IDX_TXT .. '|0|' .. tostring(datanew_HSV) if PRINT_MODE == true then print('Storing HSV text value:' .. datanew_HSV) end end --send HUE values to domoticz urlRGBLED = 'http://127.0.0.1:8080/json.htm?type=command¶m=setcolbrightnessvalue&idx=' .. Target_IDX .. '&hue=' ..Hue.. '&brightness=' ..Bri..'&saturation=' ..Sat.. '&iswhite=false' commandArray['OpenURL']= urlRGBLED -- store new HUE values in variables commandArray['Variable:Led_HUE'] = New_data else print('No change in HUE values') end end end end return end function HSVtoRGB(h, s, v) local r, g, b local i = math.floor(h * 6); local f = h * 6 - i; local p = v * (1 - s); local q = v * (1 - f * s); local t = v * (1 - (1 - f) * s); i = i % 6 if i == 0 then r, g, b = v, t, p end if i == 1 then r, g, b = q, v, p end if i == 2 then r, g, b = p, v, t end if i == 3 then r, g, b = p, q, v end if i == 4 then r, g, b = t, p, v end if i == 5 then r, g, b = v, p, q end R=round((r*255),0) G=round((g*255),0) B=round((b*255),0) return R, G, B end function RGBtoHSV(r, g, b) r, g, b = r / 255, g / 255, b / 255 local max, min = math.max(r, g, b), math.min(r, g, b) local h, s, v v = max local d = max - min if max == 0 then s = 0 else s = d / max end if max == min then h = 0 -- achromatic else if max == r then h = (g - b) / d if g < b then h = h + 6 end elseif max == g then h = (b - r) / d + 2 elseif max == b then h = (r - g) / d + 4 end h = h / 6 end return h, s, v end function round(num, idp) local mult = 10^(idp or 0) return math.floor(num * mult + 0.5) / mult end function num2hex(num) local hexstr = '0123456789ABCDEF' local s = '' while num > 0 do local mod = math.fmod(num, 16) s = string.sub(hexstr, mod+1, mod+1) .. s num = math.floor(num / 16) end if s == '' then s = '0' end return s end t = hueread(device, params, mode) processJSON(t) end end return commandArray
The time based lua script
-- this script reads the setting of 1 HUE RGB device and forwards this to a mysensor RGB dimmer -- one script will do this time based and the second script will do this on a device change, in order to capture changed made from domoticz and through the HUE bridge directly -- HUE stores the values in HSV format where the mysensor node uses RGB values for the RGB LED's so these have to be converted before forwarding -- a user variable has to be creased to store the current HUE settings (String) -- a dummy text utility has to be created to store the HSV or RGB and dimmer values for the mysensor node to request -- additional libraries for lua have to be installed -- how to do this can be found in the help wiki http://www.domoticz.com/wiki/Upload_energy_data_to_PVoutput#Install_socket_library -- or from http://www.domoticz.com/forum/viewtopic.php?f=5&t=1847&p=22638#p22638 -- for json processing I use http://regex.info/code/JSON.lua on a raspberry pi -- on a synology nas dkjson seems to do a better job http://dkolf.de/src/dkjson-lua.fsl/home -- all need to end up in /usr/local/lib/lua/5.2 commandArray = {} -- fixed values base_url = 'http://192.168.2.150/api/fd81c2245c8797cec333e351d01a3' -- hue URL and username domoticz_url = 'http://192.168.2.140:8080' --URL of domoticz server HUE_Strip_ID = 6 -- HUE ID of deviced to be replicated HUE_CURRENT = 'Led_HUE' -- uservariable (String) to store HUE setting Source_Name = 'HueStrip' -- Name of the HUE device to be copied in Domoticz Target_IDX = 229 -- IDX of target device Target_Name = 'RGB_Led' -- exact device name Target_IDX_TXT=38 -- IDX for HSV values ForwardType = 'HSV' -- HSV or RGB to be forwarded to the mysensor node PRINT_MODE = false -- when true wil print output to log and send notifications -- Only load libaries now http = require('socket.http') ltn12 = require('ltn12') json = require('JSON') io = require('io') -- set some local variables device = '' mode = 'GET' params = '' function hueread(device, operation, mode) local t = {} local url = base_url .. device local req_body = operation if PRINT_MODE == true then print(url) print(req_body) end local headers = { ["Content-Type"] = "application/json"; ["Content-Length"] = #req_body; } client, code, headers, status = http.request{url=url, headers=headers, source=ltn12.source.string(req_body), sink = ltn12.sink.table(t), method=mode} if PRINT_MODE == true then print(status) end return t end function processJSON(t) obj, pos, err = json:decode(table.concat(t),1,nil) if PRINT_MODE == true then print(table.concat(t)) print("check for error") end if err then print ("Error for HUE Bridge:", err) else if PRINT_MODE == true then print("no error") end data = '' i=HUE_Strip_ID state=obj.lights[tostring(i)].state dataHUE = data .. state.bri ..'|'.. state.hue ..'|'.. state.sat dataStatus = state.on -- checking if HUE strip is off if state.on==false then if PRINT_MODE == true then if otherdevices[Target_Name] ~= 'Off' then print('HUE LED is off, but RGB LED was on') else print('HUE LED is off, no action') end commandArray[Target_Name] = 'Off' if PRINT_MODE == true then print('Sending off switch command just to be sure') end end else -- checking if HUE strip is on but led strip is off if state.on==true then if otherdevices[Target_Name] == 'Off' then if PRINT_MODE == true then print('Switching RGB led on') end commandArray[Target_Name] = 'On' if PRINT_MODE == true then print('Hue ID checked: ' .. i) print('Status on: On') print('HUE: ' .. dataHUE) print('length of encode '..#dataHUE) end else if PRINT_MODE == true then print('RGB led already on, checking settings') end commandArray[Target_Name] = 'On' if PRINT_MODE == true then print('Sending on switch command just to be sure') end end -- Collecting color data to compare Old_data = tostring(uservariables[HUE_CURRENT]) New_data = tostring(dataHUE) if New_data ~= Old_data then print('HUE data changed') if PRINT_MODE == true then print('New data:' .. New_data) print('Old data:' ..Old_data) print('') end -- convert HUE values to HSV H=((state.hue)/65534) S=((state.sat)/254) V=((state.bri)/254) --convert HUE to domoticz values Hue=tostring(math.floor(H*360)) Sat=tostring(math.floor(S*100)) Bri=tostring(math.floor(V*100)) -- convert HSV to RGB and RGB hex values R, G, B =HSVtoRGB(H, S, V) if R >= 16 then Rhex=num2hex(R) else Rhex='0'.. num2hex(R) end if G >= 16 then Ghex=num2hex(G) else Ghex='0'.. num2hex(G) end if B >= 16 then Bhex=num2hex(B) else Bhex='0'.. num2hex(B) end RGB= R ..'|'.. G ..'|'.. B RGBhex= Rhex ..''.. Ghex ..''.. Bhex if PRINT_MODE == true then -- Reverse calculations of hue values for validation Hr, Sr, Vr =RGBtoHSV(R, G, B) Hrev=round((Hr*65536),0) Srev=round((Sr*256),0) Vrev=round((Vr*256),0) -- print all calculated data print('Hue Hue light: ' .. state.hue) print('Sat Hue light: ' .. state.sat) print('Bright Hue light: ' .. state.bri) print(' ') print('Hue domoticz: ' .. Hue) print('Sat domoticz: ' .. Sat) print('Bri domoticz: ' .. Bri) print(' ') print('H: ' .. H) print('S: ' .. S) print('V: ' .. V) print(' ') print('R: ' .. R) print('G: ' .. G) print('B: ' .. B) print('RGB: ' .. RGB) print(' ') print('Rhex: ' .. Rhex) print('Ghex: ' .. Ghex) print('Bhex: ' .. Bhex) print('RGBhex: ' .. RGBhex) print(' ') print('H reversed: ' .. Hrev) print('S reversed: ' .. Srev) print('V reversed: ' .. Vrev) end -- set LED strip if (ForwardType=='RGB') then -- store RGB as text datanew_TXT=RGBhex..";"..Bri..";" commandArray['UpdateDevice'] = Target_IDX_TXT .. '|0|' .. tostring(datanew_TXT) if PRINT_MODE == true then print('Storing RGB text value:' .. datanew_TXT) end end if (ForwardType=='HSV') then -- store HSV as text datanew_HSV=state.hue..";"..state.sat..";"..state.bri..";" commandArray['UpdateDevice'] = Target_IDX_TXT .. '|0|' .. tostring(datanew_HSV) if PRINT_MODE == true then print('Storing HSV text value:' .. datanew_HSV) end end --send HUE values to domoticz urlRGBLED = 'http://127.0.0.1:8080/json.htm?type=command¶m=setcolbrightnessvalue&idx=' .. Target_IDX .. '&hue=' ..Hue.. '&brightness=' ..Bri..'&saturation=' ..Sat.. '&iswhite=false' commandArray['OpenURL']= urlRGBLED -- store new HUE values in variables commandArray['Variable:Led_HUE'] = New_data else print('No change in HUE values') end end end end return end function HSVtoRGB(h, s, v) local r, g, b local i = math.floor(h * 6); local f = h * 6 - i; local p = v * (1 - s); local q = v * (1 - f * s); local t = v * (1 - (1 - f) * s); i = i % 6 if i == 0 then r, g, b = v, t, p end if i == 1 then r, g, b = q, v, p end if i == 2 then r, g, b = p, v, t end if i == 3 then r, g, b = p, q, v end if i == 4 then r, g, b = t, p, v end if i == 5 then r, g, b = v, p, q end R=round((r*255),0) G=round((g*255),0) B=round((b*255),0) return R, G, B end function RGBtoHSV(r, g, b) r, g, b = r / 255, g / 255, b / 255 local max, min = math.max(r, g, b), math.min(r, g, b) local h, s, v v = max local d = max - min if max == 0 then s = 0 else s = d / max end if max == min then h = 0 -- achromatic else if max == r then h = (g - b) / d if g < b then h = h + 6 end elseif max == g then h = (b - r) / d + 2 elseif max == b then h = (r - g) / d + 4 end h = h / 6 end return h, s, v end function round(num, idp) local mult = 10^(idp or 0) return math.floor(num * mult + 0.5) / mult end function num2hex(num) local hexstr = '0123456789ABCDEF' local s = '' while num > 0 do local mod = math.fmod(num, 16) s = string.sub(hexstr, mod+1, mod+1) .. s num = math.floor(num / 16) end if s == '' then s = '0' end return s end t = hueread(device, params, mode) processJSON(t) return commandArray
I use a watchdog script, where this is a simplified version of, currently I have 5 ESP units in this watchdog script
commandArray = {} PRINT_MODE = false -- when true wil print output to log and send notifications function timedifference (s) year = string.sub(s, 1, 4) month = string.sub(s, 6, 7) day = string.sub(s, 9, 10) hour = string.sub(s, 12, 13) minutes = string.sub(s, 15, 16) seconds = string.sub(s, 18, 19) t1 = os.time() t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds} difference = os.difftime (t1, t2) return difference end LastupdateESP = otherdevices_lastupdate['HeartbeatESP'] ESPdifference=timedifference (LastupdateESP) if PRINT_MODE == true then print('Lastupdate ESP ' .. LastupdateESP) print('Time difference ' .. ESPdifference) end if (ESPdifference>=130) then if (otherdevices['ESPAlive'] == 'On')then commandArray['ESPAlive'] = 'Off' CurrentTime=os.date("%Y-%m-%d %H:%M:%S") file = io.open("/home/pi/domoticz/www/log/MysensorWatchdog.log", "a") io.output(file) io.write(CurrentTime.. " Mysensor ESP connection lost" .. "\n") io.close(file) if PRINT_MODE == true then print('Writing to error log') end end end if (ESPdifference<130 and otherdevices['ESPAlive'] == 'Off')then if PRINT_MODE == true then print('ESP is a live again') end commandArray['ESPAlive'] = 'On' CurrentTime=os.date("%Y-%m-%d %H:%M:%S") file = io.open("/home/pi/domoticz/www/log/MysensorWatchdog.log", "a") io.output(file) io.write(CurrentTime.. " Mysensor ESP connection operational again" .. "\n") io.close(file) if PRINT_MODE == true then print('Writing to error log') end end commandArray['HeartbeatESP'] = 'On' return commandArray