💬 OH MySensors RGBW Controller
-
@Jan-Gatzke Good job! I have a working 2.0 Version but it lacks your new features. I will take the time and add yours to the code in my git repo :)
Thx. Those new features, however, are kind of a workaround. It would have been better if the node could request the V_RGBW value directly. MySensors supports this, but domoticz doesn't seem to. I have testet this and domoticz always returned "0" as value. And because you and me are both using domoticz, I decided to implement this feature using V_VAR1-3.
I am still thinking about the fading. I think we could get better colors if we could compensate the non linear dimming of the LEDs. With the actual sketch colors composed of mid range values could be wrong because every PWM value above 150 or so looks like almost full power. So 00AAFF almost looks like 00FFFF. AA has a value of 170 where FF is 255. This should make a big difference.
-
I have tried to get some kind of non linear fading by calculating the values for 256 steps using Excel and putting them in an array. The result is pretty good. Please test and share your opinion. ;)
/** Based on the MySensors Project: http://www.mysensors.org This sketch controls a (analog)RGBW strip by listening to new color values from a (domoticz) controller and then fading to the new color. Version 1.1 - Added save/restore of values to/from controller, removed non linear fading code Version 1.0 - Changed pins and gw definition Version 0.9 - Oliver Hilsky **/ #define MY_DEBUG #define SN "RGBW 01" #define SV "1.1" #define MY_RADIO_NRF24 // change the pins to free up the pwm pin for led control #define MY_RF24_CE_PIN 4 //<-- NOTE!!! changed, the default is 9 #define MY_RF24_CS_PIN 10 // default is 10 // Set LOW transmit power level as default, if you have an amplified NRF-module and // power your radio separately with a good regulator you can turn up PA level. #define MY_RF24_PA_LEVEL RF24_PA_LOW //Uncomment to enable repeater mode //#define MY_REPEATER_FEATURE //Uncomment to assign static node ID //#define MY_NODE_ID 9 // Load mysensors library #include <MySensors.h> // Load Serial Peripheral Interface library #include <SPI.h> // Arduino pin attached to driver pins #define RED_PIN 3 #define WHITE_PIN 9 #define GREEN_PIN 5 #define BLUE_PIN 6 #define NUM_CHANNELS 4 // how many channels, RGBW=4 RGB=3... #define CHILD_ID 1 // Smooth stepping between the values #define STEP 1 #define INTERVAL 10 MyMessage lastvalueMsg(CHILD_ID, V_VAR1); MyMessage lastisonMsg(CHILD_ID, V_VAR2); MyMessage lastdimmMsg(CHILD_ID, V_VAR3); // Stores the current color settings byte channels[4] = {RED_PIN, GREEN_PIN, BLUE_PIN, WHITE_PIN}; byte values[4] = {0, 0, 0, 0}; byte target_values[4] = {0, 0, 0, 0}; //Stores corrected values for each step from 0 to 255. See https://diarmuid.ie/blog/pwm-exponential-led-fading-on-arduino-or-other-platforms/ byte converted_values[256] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,8,8,8,8,8,9,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,13,13,13,13,14,14,14,15,15,15,16,16,17,17,17,18,18,19,19,20,20,20,21,21,22,22,23,23,24,24,25,26,26,27,27,28,29,29,30,31,31,32,33,34,34,35,36,37,38,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,56,57,58,60,61,62,64,65,67,68,70,71,73,75,76,78,80,81,83,85,87,89,91,93,95,97,99,101,104,106,108,111,113,116,118,121,123,126,129,132,135,138,141,144,147,150,154,157,161,164,168,171,175,179,183,187,191,195,200,204,209,213,218,223,228,233,238,243,249,255}; // stores dimming level byte dimming = 100; byte target_dimming = 100; // tracks if the strip should be on of off boolean isOn = false; // tracks if the strip's last status was off. This overrides isOn at startup boolean wasOff = true; //tracks if the old values have bben requested from the controller. This prevents the request from being send multipßle times in the main loop. boolean valuesrequested = false; // time tracking for updates unsigned long lastupdate = millis(); void setup() { // Set all channels to output (pin number, type) for (int i = 0; i < NUM_CHANNELS; i++) { pinMode(channels[i], OUTPUT); } // debug if (isOn) { Serial.println("RGBW is running..."); } } void presentation() { // Send the sketch version information to the gateway and Controller sendSketchInfo(SN, SV); // Register this device as Waterflow sensor present(CHILD_ID, S_RGBW_LIGHT, SN, true); } void loop() { if (!valuesrequested) { // get old values if this is just a restart Serial.println("Requesting old values..."); //Request RGBW values request( CHILD_ID, V_VAR1 ); wait(200); //Request Status request( CHILD_ID, V_VAR2 ); wait(200); //Request dimm level request( CHILD_ID, V_VAR3 ); valuesrequested = true; } // set the new light colors if (millis() > lastupdate + INTERVAL) { updateLights(); lastupdate = millis(); } } // callback function for incoming messages void receive(const MyMessage &message) { Serial.print("Got a message - "); Serial.print("Messagetype is: "); Serial.println(message.type); // acknoledgment if (message.isAck()) { Serial.println("Got ack from gateway"); } // new dim level else if (message.type == V_DIMMER or message.type == V_VAR3) { Serial.println("Dimming to "); Serial.println(message.getString()); target_dimming = message.getByte(); send(lastdimmMsg.set(target_dimming)); if (!wasOff) { // a new dimmer value also means on, no seperate signal gets send (by domoticz) isOn = true; send(lastisonMsg.set(isOn)); } } // on / off message else if (message.type == V_STATUS or message.type == V_VAR2) { Serial.print("Turning light "); isOn = message.getInt(); if (isOn) { Serial.println("on"); wasOff = false; } else { Serial.println("off"); } send(lastisonMsg.set(isOn)); } // new color value else if (message.type == V_RGBW or message.type == V_VAR1) { const char * rgbvalues = message.getString(); send(lastvalueMsg.set(rgbvalues)); inputToRGBW(rgbvalues); if (!wasOff) { // a new color also means on, no seperate signal gets send (by domoticz); needed e.g. for groups isOn = true; send(lastisonMsg.set(isOn)); } } } // this gets called every INTERVAL milliseconds and updates the current pwm levels for all colors void updateLights() { int convertedvalue=0; // update pin values -debug //Serial.println(greenval); //Serial.println(redval); //Serial.println(blueval); //Serial.println(whiteval); //Serial.println(target_greenval); //Serial.println(target_redval); //Serial.println(target_blueval); //Serial.println(target_whiteval); //Serial.println("+++++++++++++++"); // for each color for (int v = 0; v < NUM_CHANNELS; v++) { if (values[v] < target_values[v]) { values[v] += STEP; if (values[v] > target_values[v]) { values[v] = target_values[v]; } } if (values[v] > target_values[v]) { values[v] -= STEP; if (values[v] < target_values[v]) { values[v] = target_values[v]; } } } // dimming if (dimming < target_dimming) { dimming += STEP; if (dimming > target_dimming) { dimming = target_dimming; } } if (dimming > target_dimming) { dimming -= STEP; if (dimming < target_dimming) { dimming = target_dimming; } } /* // debug - new values Serial.println(greenval); Serial.println(redval); Serial.println(blueval); Serial.println(whiteval); Serial.println(target_greenval); Serial.println(target_redval); Serial.println(target_blueval); Serial.println(target_whiteval); Serial.println("+++++++++++++++"); */ // set actual pin values for (int i = 0; i < NUM_CHANNELS; i++) { if (isOn) { // normal fading //analogWrite(channels[i], dimming / 100.0 * values[i]); //Fading with corrected values see https://diarmuid.ie/blog/pwm-exponential-led-fading-on-arduino-or-other-platforms/ analogWrite(channels[i], dimming / 100.0 * converted_values[values[i]]); } else { analogWrite(channels[i], 0); } } } // converts incoming color string to actual (int) values // ATTENTION this currently does nearly no checks, so the format needs to be exactly like domoticz sends the strings void inputToRGBW(const char * input) { Serial.print("Got color value of length: "); Serial.println(strlen(input)); if (strlen(input) == 6) { Serial.println("new rgb value"); target_values[0] = fromhex (& input [0]); target_values[1] = fromhex (& input [2]); target_values[2] = fromhex (& input [4]); target_values[3] = 0; } else if (strlen(input) == 9) { Serial.println("new rgbw value"); target_values[0] = fromhex (& input [1]); // ignore # as first sign target_values[1] = fromhex (& input [3]); target_values[2] = fromhex (& input [5]); target_values[3] = fromhex (& input [7]); } else { Serial.println("Wrong length of input"); } Serial.print("New color values: "); Serial.println(input); for (int i = 0; i < NUM_CHANNELS; i++) { Serial.print(target_values[i]); Serial.print(", "); } Serial.println(""); Serial.print("Dimming: "); Serial.println(dimming); } // converts hex char to byte byte fromhex (const char * str) { char c = str [0] - '0'; if (c > 9) c -= 7; int result = c; c = str [1] - '0'; if (c > 9) c -= 7; return (result << 4) | c; } -
Thx. Those new features, however, are kind of a workaround. It would have been better if the node could request the V_RGBW value directly. MySensors supports this, but domoticz doesn't seem to. I have testet this and domoticz always returned "0" as value. And because you and me are both using domoticz, I decided to implement this feature using V_VAR1-3.
I am still thinking about the fading. I think we could get better colors if we could compensate the non linear dimming of the LEDs. With the actual sketch colors composed of mid range values could be wrong because every PWM value above 150 or so looks like almost full power. So 00AAFF almost looks like 00FFFF. AA has a value of 170 where FF is 255. This should make a big difference.
@Jan-Gatzke for Domoticz you can use V_TEXT. You can request a value and manipulate it in Lua. Also Domoticz is terrible with rgb as it only allows saturated colors.
-
I have tried to get some kind of non linear fading by calculating the values for 256 steps using Excel and putting them in an array. The result is pretty good. Please test and share your opinion. ;)
/** Based on the MySensors Project: http://www.mysensors.org This sketch controls a (analog)RGBW strip by listening to new color values from a (domoticz) controller and then fading to the new color. Version 1.1 - Added save/restore of values to/from controller, removed non linear fading code Version 1.0 - Changed pins and gw definition Version 0.9 - Oliver Hilsky **/ #define MY_DEBUG #define SN "RGBW 01" #define SV "1.1" #define MY_RADIO_NRF24 // change the pins to free up the pwm pin for led control #define MY_RF24_CE_PIN 4 //<-- NOTE!!! changed, the default is 9 #define MY_RF24_CS_PIN 10 // default is 10 // Set LOW transmit power level as default, if you have an amplified NRF-module and // power your radio separately with a good regulator you can turn up PA level. #define MY_RF24_PA_LEVEL RF24_PA_LOW //Uncomment to enable repeater mode //#define MY_REPEATER_FEATURE //Uncomment to assign static node ID //#define MY_NODE_ID 9 // Load mysensors library #include <MySensors.h> // Load Serial Peripheral Interface library #include <SPI.h> // Arduino pin attached to driver pins #define RED_PIN 3 #define WHITE_PIN 9 #define GREEN_PIN 5 #define BLUE_PIN 6 #define NUM_CHANNELS 4 // how many channels, RGBW=4 RGB=3... #define CHILD_ID 1 // Smooth stepping between the values #define STEP 1 #define INTERVAL 10 MyMessage lastvalueMsg(CHILD_ID, V_VAR1); MyMessage lastisonMsg(CHILD_ID, V_VAR2); MyMessage lastdimmMsg(CHILD_ID, V_VAR3); // Stores the current color settings byte channels[4] = {RED_PIN, GREEN_PIN, BLUE_PIN, WHITE_PIN}; byte values[4] = {0, 0, 0, 0}; byte target_values[4] = {0, 0, 0, 0}; //Stores corrected values for each step from 0 to 255. See https://diarmuid.ie/blog/pwm-exponential-led-fading-on-arduino-or-other-platforms/ byte converted_values[256] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,8,8,8,8,8,9,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,13,13,13,13,14,14,14,15,15,15,16,16,17,17,17,18,18,19,19,20,20,20,21,21,22,22,23,23,24,24,25,26,26,27,27,28,29,29,30,31,31,32,33,34,34,35,36,37,38,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,54,55,56,57,58,60,61,62,64,65,67,68,70,71,73,75,76,78,80,81,83,85,87,89,91,93,95,97,99,101,104,106,108,111,113,116,118,121,123,126,129,132,135,138,141,144,147,150,154,157,161,164,168,171,175,179,183,187,191,195,200,204,209,213,218,223,228,233,238,243,249,255}; // stores dimming level byte dimming = 100; byte target_dimming = 100; // tracks if the strip should be on of off boolean isOn = false; // tracks if the strip's last status was off. This overrides isOn at startup boolean wasOff = true; //tracks if the old values have bben requested from the controller. This prevents the request from being send multipßle times in the main loop. boolean valuesrequested = false; // time tracking for updates unsigned long lastupdate = millis(); void setup() { // Set all channels to output (pin number, type) for (int i = 0; i < NUM_CHANNELS; i++) { pinMode(channels[i], OUTPUT); } // debug if (isOn) { Serial.println("RGBW is running..."); } } void presentation() { // Send the sketch version information to the gateway and Controller sendSketchInfo(SN, SV); // Register this device as Waterflow sensor present(CHILD_ID, S_RGBW_LIGHT, SN, true); } void loop() { if (!valuesrequested) { // get old values if this is just a restart Serial.println("Requesting old values..."); //Request RGBW values request( CHILD_ID, V_VAR1 ); wait(200); //Request Status request( CHILD_ID, V_VAR2 ); wait(200); //Request dimm level request( CHILD_ID, V_VAR3 ); valuesrequested = true; } // set the new light colors if (millis() > lastupdate + INTERVAL) { updateLights(); lastupdate = millis(); } } // callback function for incoming messages void receive(const MyMessage &message) { Serial.print("Got a message - "); Serial.print("Messagetype is: "); Serial.println(message.type); // acknoledgment if (message.isAck()) { Serial.println("Got ack from gateway"); } // new dim level else if (message.type == V_DIMMER or message.type == V_VAR3) { Serial.println("Dimming to "); Serial.println(message.getString()); target_dimming = message.getByte(); send(lastdimmMsg.set(target_dimming)); if (!wasOff) { // a new dimmer value also means on, no seperate signal gets send (by domoticz) isOn = true; send(lastisonMsg.set(isOn)); } } // on / off message else if (message.type == V_STATUS or message.type == V_VAR2) { Serial.print("Turning light "); isOn = message.getInt(); if (isOn) { Serial.println("on"); wasOff = false; } else { Serial.println("off"); } send(lastisonMsg.set(isOn)); } // new color value else if (message.type == V_RGBW or message.type == V_VAR1) { const char * rgbvalues = message.getString(); send(lastvalueMsg.set(rgbvalues)); inputToRGBW(rgbvalues); if (!wasOff) { // a new color also means on, no seperate signal gets send (by domoticz); needed e.g. for groups isOn = true; send(lastisonMsg.set(isOn)); } } } // this gets called every INTERVAL milliseconds and updates the current pwm levels for all colors void updateLights() { int convertedvalue=0; // update pin values -debug //Serial.println(greenval); //Serial.println(redval); //Serial.println(blueval); //Serial.println(whiteval); //Serial.println(target_greenval); //Serial.println(target_redval); //Serial.println(target_blueval); //Serial.println(target_whiteval); //Serial.println("+++++++++++++++"); // for each color for (int v = 0; v < NUM_CHANNELS; v++) { if (values[v] < target_values[v]) { values[v] += STEP; if (values[v] > target_values[v]) { values[v] = target_values[v]; } } if (values[v] > target_values[v]) { values[v] -= STEP; if (values[v] < target_values[v]) { values[v] = target_values[v]; } } } // dimming if (dimming < target_dimming) { dimming += STEP; if (dimming > target_dimming) { dimming = target_dimming; } } if (dimming > target_dimming) { dimming -= STEP; if (dimming < target_dimming) { dimming = target_dimming; } } /* // debug - new values Serial.println(greenval); Serial.println(redval); Serial.println(blueval); Serial.println(whiteval); Serial.println(target_greenval); Serial.println(target_redval); Serial.println(target_blueval); Serial.println(target_whiteval); Serial.println("+++++++++++++++"); */ // set actual pin values for (int i = 0; i < NUM_CHANNELS; i++) { if (isOn) { // normal fading //analogWrite(channels[i], dimming / 100.0 * values[i]); //Fading with corrected values see https://diarmuid.ie/blog/pwm-exponential-led-fading-on-arduino-or-other-platforms/ analogWrite(channels[i], dimming / 100.0 * converted_values[values[i]]); } else { analogWrite(channels[i], 0); } } } // converts incoming color string to actual (int) values // ATTENTION this currently does nearly no checks, so the format needs to be exactly like domoticz sends the strings void inputToRGBW(const char * input) { Serial.print("Got color value of length: "); Serial.println(strlen(input)); if (strlen(input) == 6) { Serial.println("new rgb value"); target_values[0] = fromhex (& input [0]); target_values[1] = fromhex (& input [2]); target_values[2] = fromhex (& input [4]); target_values[3] = 0; } else if (strlen(input) == 9) { Serial.println("new rgbw value"); target_values[0] = fromhex (& input [1]); // ignore # as first sign target_values[1] = fromhex (& input [3]); target_values[2] = fromhex (& input [5]); target_values[3] = fromhex (& input [7]); } else { Serial.println("Wrong length of input"); } Serial.print("New color values: "); Serial.println(input); for (int i = 0; i < NUM_CHANNELS; i++) { Serial.print(target_values[i]); Serial.print(", "); } Serial.println(""); Serial.print("Dimming: "); Serial.println(dimming); } // converts hex char to byte byte fromhex (const char * str) { char c = str [0] - '0'; if (c > 9) c -= 7; int result = c; c = str [1] - '0'; if (c > 9) c -= 7; return (result << 4) | c; }@Jan-Gatzke the FastLED library allows for very fast math with color values. Also some very educational stuff for color manipulation in the code and documentation.
-
@Jan-Gatzke the FastLED library allows for very fast math with color values. Also some very educational stuff for color manipulation in the code and documentation.
Thx for the info. This comes 24 hours to late. :joy:
-
@pepson I wont do it because my networks is using NRFs but the kicad files are online, you could just get those and only change the radio part.
-
I dont know software kicad... and can i please you to help me for changing it to radio RFM69HW please ?
-
Ok i find:
https://www.openhardware.io/view/16/NRF2RFM69very thanks
-
What software is for file kicad_pcb ?
I download this but i can not open this file by this soft...
http://kicad-pcb.org/download/windows/Or in which file is write project PCB ?
-
What software is for file kicad_pcb ?
I download this but i can not open this file by this soft...
http://kicad-pcb.org/download/windows/Or in which file is write project PCB ?
@pepson The *.kicad_pcb file should be the pcb, the *.sch file the schematics.
You could just use the schematics to remake my project by yourself though and learn kicad on the way. Otherwise the suggested adaptor seems to be the easiest solution. -
@pepson The *.kicad_pcb file should be the pcb, the *.sch file the schematics.
You could just use the schematics to remake my project by yourself though and learn kicad on the way. Otherwise the suggested adaptor seems to be the easiest solution.But in soft kicad i dont have option to open this file... kicad can only open *.pro
-
@pepson said:
This PCB will also available to buy it as i can buy PCB to converter NRF to RFM69 ?
I am not sure if I understand your question. I am not selling the pcbs but you can buy it from dirtypcbs and support me. I guess you should be able to use it with the converter though I never did. Be sure to check dimensions first!
-
A zip with the gerber files. The version 1.3 that I used is already in their store though: http://dirtypcbs.com/store/designer/details/7078/867/mysensors-rgbw-controller-v1-3
-
@pepson What do you want to know about domoticz? It looks like every other RGB switch in domotizc depending on your used theme, just google it ;)