Piston to store position of and control blinds


#1

1) Give a description of the problem
I have modified a few blind controllers to be able to control it via ST using a Fibaro Relay Insert (FGS-222). (I’ll do a write-up of how I did it in case others may want to try it.)
Once can set the time each of the contacts of the FGS0222 close. Once that time has passed, the contact automatically opens. The idea is to open or close the blinds as the day goes on, to either keep the sun out in summer or letting it in during Winter.
The FGS-222 is a dual contact relay and I’ve wired it in such a way that Contact 1 turns the blinds in one direction, while Contact 2 turns it in the opposite direction. I have set the FGS-222 to close for a few milliseconds so that the (horizontal) blinds only move about a 5th of the total travel at every push of the Device Switch. The result is that pushing Contact 1, operates the blinds motor just long enough to turn the blinds about 1.5th of a full cycle in one direction. while 5 pushes of Contact 2, turn the blinds all the way in the opposite direction. (I can obviously increase the number of pushes required to completely turn the blinds in a particular direction by shortening the time the contacts close.

2) What is the expected behavior?
I would like to create a piston which does 2 things.
(a) It should remember the position of the blinds, depending on how many times Contact 1 or 2 were pressed (regardless of the “push” coming from the ST app or from webCoRE). I was thinking of something like a counter which counts up to 5 with every push of contact 1 and every time contact 2 is pressed, subtracting 1, so that position 1 indicates the blinds are turned all the way in one direction, while 5 indicates the blinds were turned all the way in the other direction.
(b) Once I have accomplished (a), the second part of what I hope to accomplish, will be more difficult. I would like to gradually turn the blinds to let in maximum sunlight in winter, while doing the opposite in summer. I have some ideas of how to accomplish this but don’t know which of these ideas are possible and feasible. One idea is to use a sensor to measure the amount of light coming into the room and adjust the blinds to let in the maximum amount of light (in winter).
The blinds I want to adjust, face in the direction of where the sun sets in winter (western side of the house). The sun moves over the roof of the house more or less in the middle of the day in winter. If there is a way to calculate the midpoint between sunrise and sunset (I’m sure there is), one could possibly set up a pre-defined schedule (which I’ll set up with trial and error) using that result to adjust the blinds. E.g. 1 hour after the mid-point, turn the blinds to position 3; 2 hours after mid-point, turn blinds to position 4 etc. (The complicating part will be to tell the blinds in which direction they should turn, depending on the current state of the blinds as recorded by the piston as described in (a).

Any suggestions/examples would be much appreciated.


#2

The first part is easy enough:

define
integer positionCounter

execute

IF
switch 1 IS on
AND
{positionCounter} is between 0 and 4
THEN
with location
set variable {positionCounter} = positionCounter+1
END IF

IF
switch 2 IS on
AND
{positionCounter} is between 1 and 5
THEN
with location
set variable {positionCounter} = positionCounter-1
END IF


#3

Thanks Robin. This seems simple to do.
Why do you suggest using “If switch 1 IS on” as opposed to “If switch 2 CHANGES TO on”?

Something related: Is there a reason when using the parent switch, webCoRE does not give the usual (On/Off) dropdown list?

As opposed to:


#4

In this case it makes little difference wether you use IS or CHANGES TO… it’s just a habit I have as CHANGES TO can mess with ‘waits’ when used in other pistons. In this case you don’t have any waits so they act the same.

A condition (IS) behaves the same as a trigger (CHANGES) when no other triggers are used.

Your parent switch is a custom attribute, and therefore webCoRE cannot assume it has the standard on/off states, instead it lets you type in what you want instead.


#5

Thanks @Robin.

Is it possible to display the contents of a webCoRE variable in the Device’s image in ST? Or perhaps add a tile to an existing DTH which will display the contents of such variable? (The intention being to get an indication of the position of the blinds without having to look at webCoRE when the blinds are not in view.)


#6

Certainly… I’ve just published a DTH yesterday which allows webCoRE to update a value tile.

Intended to be updated with a 24h format time, but you could send any string in the parameters and it would show in the vale tile.

Take a look at the following DTH code and piston and if you’re not sure give me another shout:


#7

This is funny. I, with the help of others on the forum, created a similar alarm but was using the DTH to set the time of the piston. Someone asked if it could not be done the other way around. I’m sure it is the same request you’re referring to. :grinning: Never imagined that I would need the same functionality a few days later.


#8

This DTH can have its time set from webCoRE OR the device preferences page.


#9

And I’m working on a DTH to just show several values… for quick referencing of webCoRE pistons etc.


#10

I’m using your modified DTH for the FGS-222.
Would it be possible to add at tile to he Parent App which shows the contents of a WebCoRE variable?


#11

Is that the one from @cjcharles that creates child devices or the original one I created?


#12

That is the one. https://community.smartthings.com/t/release-device-handler-fibaro-fgs-222-double-relay-switch/74162?u=949bfn


#13

Here is my stand alone DTH, for displaying webCoRE values.

Will take a look at the specific DTH you asked for now


#14

Your link goes to my thread, but I linked to @cjcharles’s handler from post 1 so I’m still not sure which handler you are using… do you have child devices, or is all control within the one ‘thing’


#15

Sorry Robin. I’m using the DTH which creates 2 Child Devices (which I believe is a DTH you created from one originally created by @cjcharles.)

First part of the DTH:

/**
 *  
 *	Fibaro FGS-222 Double Relay Switch Device Type
 *  
 *	Author: Chris Charles and Robin
 *	Date: 2017-07-10 
 */
 
metadata {
definition (name: "Fibaro FGS-222 Double Relay", namespace: "cjcharles0", author: "Chris Charles and Robin") {
capability "Switch"
capability "Relay Switch"
capability "Polling"
capability "Configuration"
capability "Refresh"
capability "Zw Multichannel"

attribute "switch1", "string"
attribute "switch2", "string"

#16

Anyway…

Place this at the top of the DTH, alongside the existing commands and attributes:
attribute "Value1","string"
command "changeValue1"

Place this in the tiles section:
valueTile("Value1", "device.Value1", width: 2, height: 2) { state "default", label:'${currentValue}',backgroundColor: "#00A0DC" }

Place "Value1" in the details list, after "Configure"

Place this at the very bottom of the DTH:
def changeValue1 (param1) { sendEvent("name":"Value1", "value":param1) }


#17

saw you confirmed the DTH whilst I was typing my last post… will knock it up for you.


#18

Try This:

/**
 *	Fibaro FGS-222 Double Relay Device Type Handler
 * 
 *  Plus also controls Philio PAN04 and PAN06 devices (possibly PAN08)
 *  
 *  For Philio, please configure Parameter #2, while for Fibaro you need
 *  to configure everything except Parameter #2
 *  (it should not cause a problem if you break this rule though)
 * 
 *	Author: Chris Charles and Robin
 *	Date: 2017-07-10
 */
 
metadata {
    definition (name: "Fibaro FGS-222 Double Relay", namespace: "cjcharles0", author: "Chris Charles and Robin") {
        capability "Switch"
        capability "Relay Switch"
        capability "Polling"
        capability "Configuration"
        capability "Refresh"
        capability "Zw Multichannel"

        attribute "switch1", "string"
        attribute "switch2", "string"
        attribute "Value1","string"

        command "childOn"
        command "childOff"
        command "on1"
        command "off1"
        command "on2"
        command "off2"
        command "changeValue1"

        fingerprint deviceId: "0x1001", inClusters:"0x86, 0x72, 0x85, 0x60, 0x8E, 0x25, 0x20, 0x70, 0x27"
	}

	simulator {
        status "on": "command: 2003, payload: FF"
        status "off": "command: 2003, payload: 00"

        // reply messages
        reply "2001FF,delay 100,2502": "command: 2503, payload: FF"
        reply "200100,delay 100,2502": "command: 2503, payload: 00"
    }

    tiles(scale: 2){
        multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
                tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
                    attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
                    attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
                }
        }
        standardTile("switch1", "device.switch1",canChangeIcon: true, width: 3, height: 3) {
            state "on", label: "switch1", action: "off1", icon: "st.switches.switch.on", backgroundColor: "#79b821"
            state "off", label: "switch1", action: "on1", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
        }
        standardTile("switch2", "device.switch2",canChangeIcon: true, width: 3, height: 3) {
            state "on", label: "switch2", action: "off2", icon: "st.switches.switch.on", backgroundColor: "#79b821"
            state "off", label: "switch2", action: "on2", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
        }
        standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
            state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
        }
        standardTile("configure", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
            state "default", label:"", action:"configure", icon:"st.secondary.configure"
        }
        valueTile("Value1", "device.Value1", width: 2, height: 2) { 
        	state "default", label:'${currentValue}',backgroundColor: "#00A0DC" }

        main(["switch","switch1", "switch2"])
        details(["switch","switch1","switch2","refresh","configure","Value1"])
    }
   
   
    preferences {
        input name: "Info", type: "paragraph", title:"Device Handler by @RobinWinbourne and @cjcharles", description: "Parameter Settings (Philio = #2, Fibaro = the rest!):", displayDuringSetup: false

        input name: "param1", type: "number", range: "0..255", defaultValue: "255", required: false,
            title: "Parameter No. 1 - Activate / deactivate functions ALL ON / ALL OFF. \n" +
                   "255 - ALL ON active, ALL OFF active,\n" +
                   "0 - ALL ON is not active ALL OFF is not active,\n" +
                   "1 - ALL ON is not active ALL OFF active,\n" +
                   "2 - ALL ON active ALL OFF is not active.\n" +
                   "Default value: 255."

		input name: "param2", type: "number", range: "1..3", defaultValue: "1", required: false,
            title: "Philio setting only (not needed for Fibaro)\n" +
                   "Change the physical button mode (e.g. Toggle/Momentary switch).\n" +
                   "1 - Edge mode,\n" +
                   "2 - Pulse mode,\n" +
                   "3 - Edge-Toggle mode\n" +
                   "Default value: 1."

        input name: "param3", type: "number", range: "0..1", defaultValue: "0", required: false,
            title: "Parameter No. 3 - Auto off relay after specified time, with the possibility of manual override - immediate Off after button push.  " +
                   "Available settings:\n" +
                   "0 - manual override disabled. After single button push the relay turns on and automatically turns off after specified time.,\n" +
                   "1 - manual override enabled. After single button push the relay turns on and automatically turns off after specified time. Another button push turns the relay off immediately..\n" +
                   "Default value: 0."

        input name: "param4", type: "number", range: "0..65535", defaultValue: "0", required: false,
            title: "Parameter No. 4 - Auto off for relay 1.  " +
                   "Available settings:\n" +
                   "[1 - 65535] (0,1 s – 6553,5 s) Time period for auto off, in miliseconds,\n" +
                   "0 - Auto off disabled.\n" +
                   "Default value: 0."

        input name: "param5", type: "number", range: "0..65535", defaultValue: "0", required: false,
            title: "Parameter No. 5 - Auto off for relay 2.  " +
                   "Available settings:\n" +
                   "[1 - 65535] (0,1 s – 6553,5 s) Time period for auto off, in miliseconds,\n" +
                   "0 - Auto off disabled.\n" +
                   "Default value: 0."

       input name: "param6", type: "number", range: "0..2", defaultValue: "0", required: false,
            title: "Parameter No. 6 - Sending commands to control devices assigned to 1-st association group (key no. 1).  " +
                   "NOTE: Parameter 15 value must be set to 1 to work properly. This activates the double-click functionality - dimmer/roller shutter control.\n" +
                   "Available settings:\n" +
                   "0 - commands are sent when device is turned on and off,\n" +
                   "1 - commands are sent when device is turned off. Enabling device does not send control commands. Double-clicking key sends 'turn on' command, dimmers memorize the last saved state (e.g. 50% brightness),\n" +
                   "2 - commands are sent when device is turned off. Enabling device does not send control commands. Double-clicking key sends 'turn on' command and dimmers are set to 100% brightness.\n" +
                   "Default value: 0."

		input name: "param7", type: "number", range: "0..2", defaultValue: "0", required: false,
            title: "Parameter No. 7 - Sending commands to control devices assigned to 2-st association group (key no. 2).  " +
                   "NOTE: Parameter 15 value must be set to 1 to work properly. This activates the double-click functionality - dimmer/roller shutter control.\n" +
                   "Available settings:\n" +
                   "0 - commands are sent when device is turned on and off,\n" +
                   "1 - commands are sent when device is turned off. Enabling device does not send control commands. Double-clicking key sends 'turn on' command, dimmers memorize the last saved state (e.g. 50% brightness),\n" +
                   "2 - commands are sent when device is turned off. Enabling device does not send control commands. Double-clicking key sends 'turn on' command and dimmers are set to 100% brightness.\n" +
                   "Default value: 0."

        input name: "param13", type: "number", range: "0..1", defaultValue: "0", required: false,
            title: "Parameter No. 13 - Assigns bistable key status to the device.  " +
                   "Available settings:\n" +
                   "0 - [On / Off] device changes status on key status change,\n" +
                   "1 - Device status depends on key status: ON when the key is ON.\n" +
                   "Default value: 0."

        input name: "param14", type: "number", range: "0..1", defaultValue: "1", required: false,
            title: "Parameter No. 14 - Switch type connector, you may choose between momentary and toggle switches.  " +
                   "Available settings:\n" +
                   "0 - momentary switch,\n" +
                   "1 - toggle switch.\n" +
                   "Default value: 1."

        input name: "param15", type: "number", range: "0..1", defaultValue: "0", required: false,
            title: "Parameter No. 15 - Operation of the Dimmer and Roller Shutter Controller - enabling this option allows the user to dim lighting/shut roller by associating Dimmer/Roller Shutter Controller and holding or double press of double switch (only mono-stable switch).  " +
                   "Available settings:\n" +
                   "0 - Dimmer/Roller Shutter Controller control is not active,\n" +
                   "1 - Dimmer/Roller Shutter Controller control is active.\n" +
                   "Default value: 0."

        input name: "param16", type: "number", range: "0..1", defaultValue: "1", required: false,
            title: "Parameter No. 16 - Saving the state of the device after a power failure. Fibaro Switch returns to the last position saved before a power failure.  " +
                   "Available settings:\n" +
                   "0 - Fibaro Switch does not save the state after a power failure, it returns to 'off' position,\n" +
                   "1 - Fibaro Switch saves its state before power failure.\n" +
                   "Default value: 1."

        input name: "param30", type: "number", range: "0..3", defaultValue: "3", required: false,
            title: "Parameter No. 30 - General Alarm, set for relay no. 1.  " +
                   "Available settings:\n" +
                   "0 - DEACTIVATION - the device does not respond to alarm data frames\n" +
                   "1 - ALARM RELAY ON - the device turns on after detecting an alarm,\n" +
                   "2- ALARM RELAY OFF - the device turns off after detecting an alarm,\n" +
                   "3 - ALARM FLASHING - the device periodically changes its status to the opposite, when it detects an alarm within 10 min.\n" +
                   "Default value: 3."

        input name: "param31", type: "number", range: "0..3", defaultValue: "2", required: false,
            title: "Parameter No. 31 - Alarm of flooding with water, set for relay no. 1.  " +
                   "Available settings:\n" +
                   "0 - DEACTIVATION - the device does not respond to alarm data frames\n" +
                   "1 - ALARM RELAY ON - the device turns on after detecting an alarm,\n" +
                   "2- ALARM RELAY OFF - the device turns off after detecting an alarm,\n" +
                   "3 - ALARM FLASHING - the device periodically changes its status to the opposite, when it detects an alarm within 10 min.\n" +
                   "Default value: 2."

        input name: "param32", type: "number", range: "0..3", defaultValue: "3", required: false,
            title: "Parameter No. 32 - Smoke, CO, CO2 Alarm. Set for relay no. 1.  " +
                   "Available settings:\n" +
                   "0 - DEACTIVATION - the device does not respond to alarm data frames\n" +
                   "1 - ALARM RELAY ON - the device turns on after detecting an alarm,\n" +
                   "2- ALARM RELAY OFF - the device turns off after detecting an alarm,\n" +
                   "3 - ALARM FLASHING - the device periodically changes its status to the opposite, when it detects an alarm within 10 min.\n" +
                   "Default value: 3."

        input name: "param33", type: "number", range: "0..3", defaultValue: "1", required: false,
            title: "Parameter No. 33 - Temperature Alarm, set for relay no. 1.  " +
                   "Available settings:\n" +
                   "0 - DEACTIVATION - the device does not respond to alarm data frames\n" +
                   "1 - ALARM RELAY ON - the device turns on after detecting an alarm,\n" +
                   "2- ALARM RELAY OFF - the device turns off after detecting an alarm,\n" +
                   "3 - ALARM FLASHING - the device periodically changes its status to the opposite, when it detects an alarm within 10 min.\n" +
                   "Default value: 1."

        input name: "param40", type: "number", range: "0..3", defaultValue: "3", required: false,
            title: "Parameter No. 40 - General Alarm, set for relay no. 2.  " +
                   "Available settings:\n" +
                   "0 - DEACTIVATION - the device does not respond to alarm data frames\n" +
                   "1 - ALARM RELAY ON - the device turns on after detecting an alarm,\n" +
                   "2- ALARM RELAY OFF - the device turns off after detecting an alarm,\n" +
                   "3 - ALARM FLASHING - the device periodically changes its status to the opposite, when it detects an alarm within 10 min.\n" +
                   "Default value: 3."

        input name: "param41", type: "number", range: "0..3", defaultValue: "2", required: false,
            title: "Parameter No. 41 - Alarm of flooding with water, set for relay no. 2.  " +
                   "Available settings:\n" +
                   "0 - DEACTIVATION - the device does not respond to alarm data frames\n" +
                   "1 - ALARM RELAY ON - the device turns on after detecting an alarm,\n" +
                   "2- ALARM RELAY OFF - the device turns off after detecting an alarm,\n" +
                   "3 - ALARM FLASHING - the device periodically changes its status to the opposite, when it detects an alarm within 10 min.\n" +
                   "Default value: 2."

        input name: "param42", type: "number", range: "0..3", defaultValue: "3", required: false,
            title: "Parameter No. 42 - Smoke, CO, CO2 Alarm. Set for relay no. 2.  " +
                   "Available settings:\n" +
                   "0 - DEACTIVATION - the device does not respond to alarm data frames\n" +
                   "1 - ALARM RELAY ON - the device turns on after detecting an alarm,\n" +
                   "2- ALARM RELAY OFF - the device turns off after detecting an alarm,\n" +
                   "3 - ALARM FLASHING - the device periodically changes its status to the opposite, when it detects an alarm within 10 min.\n" +
                   "Default value: 3."

        input name: "param43", type: "number", range: "0..3", defaultValue: "1", required: false,
            title: "Parameter No. 43 - Temperature Alarm, set for relay no. 2.  " +
                  "Available settings:\n" +
                   "0 - DEACTIVATION - the device does not respond to alarm data frames\n" +
                   "1 - ALARM RELAY ON - the device turns on after detecting an alarm,\n" +
                   "2- ALARM RELAY OFF - the device turns off after detecting an alarm,\n" +
                   "3 - ALARM FLASHING - the device periodically changes its status to the opposite, when it detects an alarm within 10 min.\n" +
                   "Default value: 1."

        input name: "param39", type: "number", range: "0..65535", defaultValue: "600", required: false,
            title: "Parameter No. 39 - Active flashing alarm time. " +
                   "This parameter allows to set time parameter used in timed modes.\n" +
                   "Available settings:\n" +
                   "[1-65535][ms].\n" +
                   "Default value: 600."

/*    input name: "paramAssociationGroup1", type: "bool", defaultValue: true, required: true,
             title: "The Fibaro Sigle Switch provides the association of three groups.\n\n" +
                    "2nd group is assigned to key no. 1.\n" +
                    "Default value: true"

        input name: "paramAssociationGroup2", type: "bool", defaultValue: true, required: true,
             title: "2nd group is assigned to key no. 2.\n" +
                    "Default value: true"

        input name: "paramAssociationGroup3", type: "bool", defaultValue: false, required: true,
             title: "3rd group reports state of devices. Only one device can be associated to this group.\n" +
                    "Default value: false"*/
    }
}

def parse(String description) {
    def result = []
    def cmd = zwave.parse(description)
    if (cmd) {
        result += zwaveEvent(cmd)
        log.debug "Parsed ${cmd} to ${result.inspect()}"
    } else {
        log.debug "Non-parsed event: ${description}"
    }
    return result
}


def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
	sendEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital")
    def result = []
    result << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format()
    result << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2, commandClass:37, command:2).format()
    response(delayBetween(result, 1000)) // returns the result of reponse()
}

def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd)
{
    sendEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital")
    def result = []
    result << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format()
    result << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2, commandClass:37, command:2).format()
    response(delayBetween(result, 1000)) // returns the result of reponse()
}


def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCapabilityReport cmd) 
{
    log.debug "multichannelv3.MultiChannelCapabilityReport $cmd"
    if (cmd.endPoint == 2 ) {
        def currstate = device.currentState("switch2").getValue()
        if (currstate == "on")
        	sendEvent(name: "switch2", value: "off", isStateChange: true, display: false)
        else if (currstate == "off")
        	sendEvent(name: "switch2", value: "on", isStateChange: true, display: false)
    }
    else if (cmd.endPoint == 1 ) {
        def currstate = device.currentState("switch1").getValue()
        if (currstate == "on")
        sendEvent(name: "switch1", value: "off", isStateChange: true, display: false)
        else if (currstate == "off")
        sendEvent(name: "switch1", value: "on", isStateChange: true, display: false)
    }
}

def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
   def map = [ name: "switch$cmd.sourceEndPoint" ]
   def curswitch, curstate
   
   switch(cmd.commandClass) {
      case 32:
         if (cmd.parameter == [0]) {
            map.value = "off"
         }
         if (cmd.parameter == [255]) {
            map.value = "on"
         }
         createEvent(map)
         break
      case 37:
         if (cmd.parameter == [0]) {
            map.value = "off"
         }
         if (cmd.parameter == [255]) {
            map.value = "on"
         }
         curstate = map.value
         curswitch = cmd.sourceEndPoint
         break
    }
    
    //Now if there is a child device then send it a state update
    try {
        def childDevice = getChildDevices()?.find { it.deviceNetworkId == "$device.deviceNetworkId-sw${curswitch}"}
           if (childDevice)
              childDevice.sendEvent(name: "switch", value: curstate)
    } catch (e) {
        log.error "Couldn't find child device, probably doesn't exist and hence no problem: ${e}"
    }
    
    
//    childDevices?.each { childDevice ->
//    	//log.debug childDevice.deviceNetworkId //log the devices as you cycle through them
//        if (childDevice) {
//            if (childDevice.deviceNetworkId == "$device.deviceNetworkId-sw${curswitch}") {
//                childDevice.sendEvent(name: "switch", value: curstate)
//            }
//        }
//    }
    
    def events = [createEvent(map)]
    if (map.value == "on") {
            events += [createEvent([name: "switch", value: "on"])]
    } else {
         def allOff = true
         (1..2).each { n ->
             if (n != cmd.sourceEndPoint) {
                 if (device.currentState("switch${n}").value != "off") allOff = false
             }
         }
         if (allOff) {
             events += [createEvent([name: "switch", value: "off"])]
         }
    }
    events
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
    // This will capture any commands not handled by other instances of zwaveEvent
    // and is recommended for development so you can see every command the device sends
    return createEvent(descriptionText: "${device.displayName}: ${cmd}")
}

def zwaveEvent(physicalgraph.zwave.commands.switchallv1.SwitchAllReport cmd) {
   log.debug "SwitchAllReport $cmd"
}

def refresh() {
	def cmds = []
    cmds << zwave.manufacturerSpecificV2.manufacturerSpecificGet().format()
	cmds << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format()
    cmds << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2, commandClass:37, command:2).format()
	delayBetween(cmds, 1000)
}

def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
	def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
	log.debug "msr: $msr"
    updateDataValue("MSR", msr)
}

def poll() {
	def cmds = []
	cmds << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format()
    cmds << zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2, commandClass:37, command:2).format()
	delayBetween(cmds, 1000)
}

def configure() {
	log.debug "Executing 'configure'"
    delayBetween([
          zwave.configurationV1.configurationSet(parameterNumber:1, configurationValue:[param1.value]).format(),
          //The following parameter (#2) is only used for Philio devices, and does not interfere with the Fibaro
          zwave.configurationV1.configurationSet(parameterNumber:2, configurationValue:[param2.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:3, configurationValue:[param3.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:4, configurationValue:[param4.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:5, configurationValue:[param5.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:6, configurationValue:[param6.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:7, configurationValue:[param7.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:13, configurationValue:[param13.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:14, configurationValue:[param14.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:15, configurationValue:[param15.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:16, configurationValue:[param16.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:30, configurationValue:[param30.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:31, configurationValue:[param31.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:32, configurationValue:[param32.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:33, configurationValue:[param33.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:39, configurationValue:[param39.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:40, configurationValue:[param40.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:41, configurationValue:[param41.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:42, configurationValue:[param42.value]).format(),
          zwave.configurationV1.configurationSet(parameterNumber:43, configurationValue:[param43.value]).format(),
          zwave.associationV2.associationSet(groupingIdentifier:1, nodeId:[zwaveHubNodeId]).format(),
          zwave.associationV2.associationSet(groupingIdentifier:2, nodeId:[zwaveHubNodeId]).format(),
          zwave.associationV2.associationSet(groupingIdentifier:3, nodeId:[zwaveHubNodeId]).format(),
          
    ])
}

/**
* Triggered when Done button is pushed on Preference Pane
*/
def updated()
{
	log.debug "Preferences have been changed. Attempting configure() and update"
    def cmds = configure()

    //Used to use 'if (!childDevices)' but that function no longer works reliably
	createChildDevices()
	
    response(cmds)
}

def childRefresh(String dni) {
    log.debug "childRefresh($dni)"
    refresh()
}
def childOn(String dni) {
    log.debug "childOn($dni)"
    def switchnum = "on${channelNumber(dni)}"
    "$switchnum"()
}
def childOff(String dni) {
    log.debug "childOff($dni)"
    def switchnum = "off${channelNumber(dni)}"
    "$switchnum"()
}

def on() { 
   delayBetween([
        zwave.switchAllV1.switchAllOn().format(),
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format(),
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2, commandClass:37, command:2).format()
    ], 1000)
}
def off() {
   delayBetween([
        zwave.switchAllV1.switchAllOff().format(),
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format(),
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:2, commandClass:37, command:2).format()
    ], 1000)
}

def on1() {
    delayBetween([
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:1, parameter:[255]).format(),
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format()
    ], 1000)
}

def off1() {
    delayBetween([
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:1, parameter:[0]).format(),
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:1, destinationEndPoint:1, commandClass:37, command:2).format()
    ], 1000)
}

def on2() {
    delayBetween([
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:2, destinationEndPoint:2, commandClass:37, command:1, parameter:[255]).format(),
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:2, destinationEndPoint:2, commandClass:37, command:2).format()
    ], 1000)
}

def off2() {
    delayBetween([
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:2, destinationEndPoint:2, commandClass:37, command:1, parameter:[0]).format(),
        zwave.multiChannelV3.multiChannelCmdEncap(sourceEndPoint:2, destinationEndPoint:2, commandClass:37, command:2).format()
    ], 1000)
}

private channelNumber(String dni) {
	dni.split("-sw")[-1] as Integer
}

private void createChildDevices() {
	state.oldLabel = device.label
     try {
        for (i in 1..2) {
            try {
            	log.debug "Trying to create child switch if it doesn't already exist ${i}"
                def currentchild = getChildDevices()?.find { it.deviceNetworkId == "${device.deviceNetworkId}-sw${i}"}
                if (currentchild == null) {
					addChildDevice("erocm123", "Switch Child Device", "${device.deviceNetworkId}-sw${i}", device.hub.id,
						[completedSetup: true, name: "${device.displayName} (S${i})", label: "${device.displayName} (S${i})", isComponent: false])
                }
            } catch (e) {
                log.debug "Error adding child switch ${i}: ${e}"
            }
        }
    } catch (er) {
	    log.debug "Child creation failed for some reason: ${er}"
    }
}

def changeValue1 (param1) { 
sendEvent("name":"Value1", "value":param1) }

#19

It works exactly as I had hoped!
This is really fantastic. Thank you very much for your time!


#20

great (I didn’t test it lol)

btw… If you don’t like the blue circle in the tile, just delete,backgroundColor: "#00A0DC"

You can also try resizing the tile if it helps things fit better.