My MySensors RGBW plug in has an init problem
-
I've created a RGB(W) led strip MySensors controller which interacts with the RGB color wheel plug in from MiOS Marketplace.
The problem i have with it is that the the Arduino plug in does not initialize with MiOS plug in as "slave" plug in.
It is made by vosmont and can be found here and i've added MyS support (see below)If someone can help me by fixing the init problem it would be really nice, but so far.
i did make a small work around (tested with UI5 Vera 3):
1 make sure both Arduino and the MiOS RGB controller module are installed.
2 start MySensors inclusion
3 reset MySensors RGB module
4 Two devices will (should) be detected and appear. (a MYS controller and a RGB color wheel)
5 Remember the RBV modules 'altid' (wrench-icon, Advanced-tab), this looks like "6;1"
6 Remember the Device ID of the MYS Arduindo master plug in
7 Now delete the RGB color wheel (trash can icon)
8 Create a new device (APPS -> Develop Apps -> Create device)
9 Description field: <give a usefull name> like RGB strip
Upnp Device Filename field : D_RGBController1.xml
No parent device !!!
10 Press the Create device button
11 Press the reload button, wait for the system becomes stable
12 Change the setting of te RGB controller (wrench-icon, Settings-tab)
13 Select: MySensors RGBW
Arduino plugin Id: <enter ID remembered and step 6>
RGB Node altid: <enter ID remembered and step 5>
14 Press save button
15 Now the color wheel can be usedTo be able to control MyS RGB modules the following coded is added to L_RGBController1.lua after line 1004 (before Color transition management)
-- MySensor RGB(W) RGBDeviceTypes["MYS-RGBW"] = { getParameters = function (lul_device) return { name = "MySensors RGBW", settings = { { variable = "ArduinoId", name = "Arduino plugin Id", type = "string" }, { variable = "RadioId", name = "RGB Node altid", type = "string" } } } end, getColorChannelNames = function (lul_device) return {"red", "green", "blue", "warmWhite"} end, getAnimationProgramNames = function() return { "Rainbow slow", "Rainbow medium", "Rainbow fast", "Random slow colors", "Random medium colors", "Random fast colors", "RGB fade slow colors", "RGB fade medium colors", "RGB fade fast colors", "Multicolor fade slow colors", "Multicolor fade medium colors", "Multicolor fade fast colors", "Current color flash slow colors", "Current color flash medium colors", "Current color flash fast colors", } end, init = function (lul_device) debug("MYS-RGBW.init", "Init for device #" .. tostring(lul_device)) pluginParams.rgbArduinoId = tonumber(getVariableOrInit(lul_device, SID.RGB_CONTROLLER, "ArduinoId", "")) pluginParams.rgbRadioId = getVariableOrInit(lul_device, SID.RGB_CONTROLLER, "RadioId", "") return true end, setStatus = function (lul_device, newTargetValue) debug("MYS.setStatus", "Set status '" .. tostring(newTargetValue) .. "' for device #" .. tostring(lul_device)) if (tostring(newTargetValue) == "1") then debug("MYS.setStatus", "Switches on ") local formerColor = luup.variable_get(SID.RGB_CONTROLLER, "Color", lul_device):gsub("#","") luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {variableId = "RGBW", value = formerColor, radioId = pluginParams.rgbRadioId}, pluginParams.rgbArduinoId) luup.variable_set(SID.SWITCH, "Status", "1", lul_device) else debug("MYS.setStatus", "Switches off") luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {variableId = "LIGHT", value = "0", radioId = pluginParams.rgbRadioId}, pluginParams.rgbArduinoId) luup.variable_set(SID.SWITCH, "Status", "0", lul_device) end end, setColor = function (lul_device, color) colorString = tostring(color) debug("MYS.setColor", "Set RGBW color #" .. colorString .. " for device #" .. tostring(lul_device)) luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {variableId = "RGBW", value = colorString, radioId = pluginParams.rgbRadioId}, pluginParams.rgbArduinoId) end, startAnimationProgram = function (lul_device, programId, programName) if ((programName ~= nil) and (programName ~= "")) then --debug("MYS.startAnimationProgram", "Start animation program '" .. programName .. "'") mode = 0 if string.match(programName, "Random") then mode = 0x01 end if string.match(programName, "RGB fade") then mode = 0x02 end if string.match(programName, "Multicolor fade") then mode = 0x03 end if string.match(programName, "Current color flash") then mode = 0x04 end if string.match(programName, "slow") then mode = 0x10 + mode end if string.match(programName, "medium") then mode = 0x20 + mode end if string.match(programName, "fast") then mode = 0x30 + mode end debug("MYS.startAnimationProgram", "Start animation program '" .. programName .. "' " .. tostring(mode)) luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {variableId = "VAR_1", value = tostring(mode), radioId = pluginParams.rgbRadioId}, pluginParams.rgbArduinoId) else debug("MYS.startAnimationProgram", "Stop animation program") luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {variableId = "VAR_1", value = "00", radioId = pluginParams.rgbRadioId}, pluginParams.rgbArduinoId) setColorTarget(lul_device, "") end end }
And this is the MyS RGB color strip plugin
// RBG led strip plug in. // by Bart Eversdijk (c) 2015. #include <MySensor.h> #include <SPI.h> // If not defined RGB is used otherwise RGBW #define RGBW 1 #define RED 3 // Arduino PWM pin for Red #define GREEN 5 // Arduino PWM pin for Green #define BLUE 6 // Arduino PWM pin for Blue #define WHITE 7 // Arduino PWM pin for White (ilumination) enum ANIMATIOMODES {RAINBOW=0,RANDONMIZE,FADERGB,FADEMULTICOLR,FLASHCOLOR,LAST_PROGRAM}; byte FADE_RGB_COLOR_MODES[] = {0b0010,0b0011,0b0100,0b0101,0b1000,0b1001, 0xFF}; byte FADE_MULTI_COLOR_MODES[] = {0b0010,0b0011,0b0110,0b0111,0b0100,0b0101,0b1100,0b1101,0b1000,0b1001,0b1010,0b1011,0xFF}; #ifdef RGBW #define NODENAME "RGBW node" #define NODETYPE S_RGBW_LIGHT byte rgb_pins[] = {RED, GREEN, BLUE, WHITE}; #else #define NODENAME "RGB node" #define NODETYPE S_RGB_LIGHT byte rgb_pins[] = {RED, GREEN, BLUE}; #endif byte ledOffValues[] = {0, 0, 0, 0}; byte rgb_values[] = {0, 0, 0, 0}; #define NODEID 2 // Assigning the node id #define SUBID 1 // sensor number needed in the custom devices set up void incomingMessage(const MyMessage &message); #define NUM_OF_COLORS sizeof(rgb_pins) int speedtable[] = { 0, 100, 50, 2 }; #define NUM_OF_SPEEDS sizeof(speedtable) struct { byte values[4]; byte speedsetting; byte mode; bool status; } rgb = { {0,0,0,0}, 0, RAINBOW, false}; bool flashOn = true; int syscounter = 0; int lastUpdate = 0; bool newSetting = false; MySensor gw; void setup() { // Initialize library and add callback for incoming messages gw.begin(incomingMessage, AUTO /*NODEID*/); // Send the sketch version information to the gateway and Controller gw.sendSketchInfo(NODENAME, "1.1"); // Register the sensor to gw gw.present(SUBID, NODETYPE); // Set the rgb(w) pins in output mode for (int i = 0; i < NUM_OF_COLORS; i++) { pinMode(rgb_pins[i], OUTPUT); } recallEeprom(); setLedValues(rgb.values, true); Serial.println("Init done"); } void loop() { // Alway process incoming messages whenever possible gw.process(); if (speedtable[rgb.speedsetting] > 0) { if ((syscounter % speedtable[rgb.speedsetting]) == 0) { switch (rgb.mode) { case RAINBOW: animateRainbowStep(); break; case FADERGB: animateFadeColorStep(FADE_RGB_COLOR_MODES); break; case FADEMULTICOLR: animateFadeColorStep(FADE_MULTI_COLOR_MODES); break; case FLASHCOLOR: setLedValues(flashOn ? ledOffValues : rgb.values, false); flashOn = !flashOn; break; case RANDONMIZE: long number = random(0, 0xFFFFFF); rgb_values[0] = number >> 16 & 0xFF ; rgb_values[1] = number >> 8 & 0xFF ; rgb_values[2] = number & 0xFF; setLedValues(rgb_values, false); break; } } delay(rgb.mode == RANDONMIZE || rgb.mode == FLASHCOLOR ? 50 : 1); } if (newSetting && (lastUpdate + 30000 < syscounter)) { // Wait for a couple of seconds be fore actual storing the current setting in to EEPROM // This will save the EEPROM's life time, when playing around with colors Serial.println(" Store EERPOM"); storeEeprom(); newSetting = false; } delay(1); syscounter++; } void animateRainbowStep() { static float counter = 0; float pi = 3.14159; counter++; rgb_values[0] = map(sin(counter/100 )*1000,-1000,1000,0,255); rgb_values[1] = map(sin(counter/100 + pi*2/3)*1000,-1000,1000,0,255); rgb_values[2] = map(sin(counter/100 + pi*4/3)*1000,-1000,1000,0,255); setLedValues(rgb_values, false); } void animateFadeColorStep(byte *modes) { static int modecnt = 0; if (updateRGBValues(modes[modecnt] >> 1, (modes[modecnt] & 0x1) == 0x1)) { modecnt = (modes[modecnt+1] == 0xFF ? 0 : modecnt + 1); } } bool updateRGBValues(byte mode, bool down) { bool endReached = false; for (byte i = 0; i < 3; i++) { if (((mode >> i) & 0x1) == 0x1) { rgb_values[i] += (down ? -1 : 1); endReached |= (down && (rgb_values[i] == 0x00)) || (!down && (rgb_values[i] == 0xFF)); } } setLedValues(rgb_values, false); return endReached; } void incomingMessage(const MyMessage &message) { if (message.type == V_RGB || message.type == V_RGBW) { // starting to process the hex code String hexstring = message.getString(); long number; #ifdef RGBW char white[3]; white[0] = hexstring[6]; white[1] = hexstring[7]; white[2] = 0; number = (long) strtol( &white[0], NULL, 16); rgb.values[3] = number & 0xFF; #endif hexstring[6] = 0; number = (long) strtol( &hexstring[0], NULL, 16); rgb.values[0] = number >> 16 & 0xFF ; rgb.values[1] = number >> 8 & 0xFF ; rgb.values[2] = number & 0xFF; rgb.speedsetting = 0; setLedValues(rgb.values, true); lastUpdate = syscounter; newSetting = true; } if (message.type == V_STATUS) { if (message.getBool()) { Serial.println("ON: Switch to last known color values"); setLedValues(rgb_values, true); } else { Serial.println("OFF: Switch colors off"); setLedValues(ledOffValues, true); } rgb.speedsetting = 0; rgb.status = message.getBool(); lastUpdate = syscounter; newSetting = true; } if (message.type == V_VAR1) { Serial.println("Set speed and program value"); byte newsetting = message.getByte(); rgb.speedsetting = (newsetting >> 4) & 0x0F; byte newmode = newsetting & 0x0F; if (newmode != rgb.mode) { for (byte i = 0; i < NUM_OF_COLORS; i++) { rgb_values[i] = 0; } rgb.mode = newmode; } if (rgb.speedsetting > 0) { rgb.status = true; } lastUpdate = syscounter; newSetting = true; Serial.print("Data 0x"); Serial.print(newsetting, HEX); Serial.print(" speed:"); Serial.print(rgb.speedsetting); Serial.print(" mode:"); Serial.println(rgb.mode); } } void setLedValues(byte *rgb, bool show) { for (int i = 0; i < NUM_OF_COLORS; i++) { analogWrite(rgb_pins[i], rgb[i]); } if (show) { Serial.print("Red: " ); Serial.print(rgb[0], HEX); Serial.print(" Green: " ); Serial.print(rgb[1], HEX); Serial.print(" Blue: " ); Serial.print(rgb[2], HEX); #ifdef RGBW Serial.print(" White is " ); Serial.print(rgb[3], HEX); #endif Serial.println(); } } void storeEeprom() { byte address = 0; byte *p = (byte *)&(rgb); for (byte i = 0; i < sizeof(rgb); i++) { gw.saveState(address++, p[i]); } } void recallEeprom() { byte address = 0; byte *p = (byte *)&(rgb); for (byte i = 0; i < sizeof(rgb); i++) { p[i] = gw.loadState(address++); } }
Adding a reference to the MiOS forum about this plug in:
http://forum.micasaverde.com/index.php/topic,32613.0.html
-
Nice work @BartE.
If you'd like you can perhaps incorporate this in the MySensors plugin? Or ask vosmont to pull your additions?
-
Thx @hek
I'm not sure what you mean by incorporate it in the MySensors plug in, but i did make a pull-request to vosmont.
I hope he can help me with fixing the initialize issue, for some reason the MySensor plug in does not start when the RGBcontroller is configured as slave. I took me quite some time figuring this out but no luck.
-
I have a vague memory of trying setting up a VariableContainer(plugin) as child-device in MySensors way back. But it didn't work either. I don't think a plugin in Vera can delegate commands to child devices (the build in devices is the exception).
That's why I think you have to move the parts needed from vosmont's device into the MySensors plugin. The GUI/descriptor files can of course be reused.
@akbooer might have some more insight to the Vera mysteries.
-
Happy to help. I've played a bit with @vosmont's RGB plugin when getting it to run under openLuup. It would be best if he could add a new device as part of the standard plugin - it does have some very specific code for different manufacturers. I guess I need to take a closer look at the workflow in the OP and try and understand what is needed and what is not working.
-
@akbooer that would be really great if you could help.
What i see is that Vera calls the initialized (startup) function of the child devices though the parent device. So in this specific case the RGBController lua startup function is called with the lul_device id of the MySensors device and the startup function of the child plugin is NOT called.
So i modified the RGB controller startup function (L_RGBController1.lua) with a check if it was called for a child or for itself as parent.
function startup (lul_device) log("startup", "Start plugin '" .. PLUGIN_NAME .. "' (v" .. PLUGIN_VERSION .. ")") -- Update static JSON file if updateStaticJSONFile(lul_device, PLUGIN_NAME .. "1") then warning("startup", "'device_json' has been updated : reload LUUP engine") luup.reload() return false, "Reload LUUP engine" end -- Init if luup.devices[lul_device].device_type == "urn:schemas-upnp-org:device:RGBController:1" then log("startup", "Found RGB master #" .. lul_device) initPluginInstance(lul_device) -- ... and now my watch begins (setting changes) luup.variable_watch("initPluginInstance", SID.RGB_CONTROLLER, "DeviceType", lul_device) luup.variable_watch("onDebugValueIsUpdated", SID.RGB_CONTROLLER, "Debug", lul_device) else -- Look for a child RGB device, which need to start up for child_id, v in pairs(luup.devices) do -- if I am the parent device of a child RGBController start it up if v.device_num_parent == lul_device and v.device_type == "urn:schemas-upnp-org:device:RGBController:1" then log("startup", "Found RGB child #" .. child_id) initPluginInstance(child_id) -- ... and now my watch begins (setting changes) luup.variable_watch("initPluginInstance", SID.RGB_CONTROLLER, "DeviceType", child_id) luup.variable_watch("onDebugValueIsUpdated", SID.RGB_CONTROLLER, "Debug", child_id) end end end if (luup.version_major >= 7) then luup.set_failure(0, lul_device) end return true end
This does NOT do the trick, i think the MySensors device is not ready (initialized) at the moment the RGB child start up is called. I even copied all action implementations (with dummy debug log) from the I_RGBController1.xml to I_Arduino1.xml so the "no implementation errors" where all gone.
Maybe the L_Arduino.lua needs to be adapted so that the RGB-startup function is called when MySensors is ready or implement a delayed startup for child devices in L_RGBController1.lua
I'm not sure...
-
Just to start again from the beginning, you are trying to get the RGBW Controller plugin to work with MySensors RGBW devices. What I don't know is how MySensors presents an RGBW device - I am assuming you get a node with 4 child dimmers, but perhaps not? This is what a native Vera multi-colour dimmer typically does (eg. Fibaro.)
One problem I foresee is that the MySensors plugin is parent to all the MySensors devices, be they actual nodes or individual sensors, so you don't get the same logical grouping with one Vera RGBW device controlling its separate R G B W children (which is what, I think, @vosmont's controller requires.)
-
@akbooer: No, since version 1.5 MySensors supports RGB and RGBW devices and in L_Arduino.lua these devices are created with D_RGBController1.xml. This is also the definition file name of vosmont's RGB-controller (coincident or not?).
So one child is presented of type RGB or RGBW showing the vosmont's RGB color-wheel, the code i did write for the RGB-controller directly control's the RGB MyS device with MyS message's.
luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {variableId = "RGBW", value = formerColor, radioId = pluginParams.rgbRadioId}, pluginParams.rgbArduinoId)
This part of the code is working.
You are right an alternative could be, represent 3 or 4 dimmers and configure vosmont RGB module so it controls these 3 or 4 dimmers like Fibaro. But i do like the idea of having only one tile with the color wheel.
-
@BartE OK, so the device D_RGBController1.xml is actually a child of the Arduino plugin, which handles (with your changes) the action call you showed. The problem, then is that @vosmont's plugin does not recognise this device as one it can control? Or is it that you are expecting, somehow, the colour wheel to work directly with the MYSensor plugin?
Sorry to be so dim about this, but I'd hate to be chasing up the wrong tree.
-
@akbooer the second option, i expect the color wheel to work directly with the MySensor plugin/Arduino. Like some other supported RGB devices.
To do so i've created a new type of device in vosmont's plugin called "MYS-RGBW", this one you can select in the RGBcontroller and as work around one has to set the MySensor plugin id and the radio id of the RGB device. But when it is created as child device this information should be known to the plugin.
So the problem is NOT controlling the device, but having the RGBController to startup correctly as child.
-
@BartE said:
So the problem is NOT controlling the device, but having the RGBController to startup correctly as child.
OK, here's my confusion: you can't have the Arduino plugin AND the RGBW Controller plugin both controlling the RGBW device. By definition, it is a child of the Arduino plugin and all functionality for that child device has to be provided by the parent. Are there, perhaps, some actions defined in the services or implementation file which are not, in fact, implemented by your additional code in the Arduino plugin?