Hi,
I am new to openHAB but actually very impressed about it. It took some time to understand the concept behind. Thanks for the great binding and thanks to the community for sharing posts, comments and code snippets.
Now it’s time to give back something, so I would like to share my config with you. Maybe this will help someone who is in the same situation as I was a few days ago. Any comments and improvements are welcome!
This is my requirement:
- select one or more rooms (=segments) or zones
- preserve order from manual selection. Example: Select rooms in this order: 1, 5, 3. Cleaning will start with room 1 and finish with room 3
- in addition to select each room individually, all rooms may be selected as well
- runs (for me) with a Roborock S5 Max
- my wife is able to control it
The result looks like this:
rockrobo|433x500
Here is my items file:
// ----------------------------------------------------------------------------
// Zonenreinigung
// ----------------------------------------------------------------------------
Group gZoneControl "Zonenreinigung" <fan> (gVac)
Group gZone "Zonen" <group> (gZoneControl)
Group:DateTime:LATEST gZoneLastUpdate "Letzte Änderung [%s]" <time> (gZone)
Group gZoneSwitch "Schalter" <switch> (gZone)
Group:Switch:AND(ON,OFF) gAllZones "Alle Zonen" <switch>
Group gEsstisch "Esstisch - Gruppe" <status> (gZone)
Switch zEsstisch "Esstisch" <girl_2> (gEsstisch, gZoneSwitch)
DateTime zEsstischLastUpdate "Esstisch - letzte Änderung [%s]" <time> (gEsstisch, gZoneLastUpdate)
Group gKueche "Küche - Gruppe" <status> (gZone)
Switch zKueche "Küche" <kitchen> (gKueche, gZoneSwitch, gAllZones)
DateTime zKuecheLastUpdate "Küche - letzte Änderung [%s]" <time> (gKueche, gZoneLastUpdate)
Group gToilette "Toilette - Gruppe" <status> (gZone)
Switch zToilette "Toilette" <toilet> (gToilette, gZoneSwitch, gAllZones)
DateTime zToiletteLastUpdate "Toilette - letzte Änderung [%s]" <time> (gToilette, gZoneLastUpdate)
Group gSpeisekammer "Speisekammer - Gruppe" <status> (gZone)
Switch zSpeisekammer "Speisekammer" <pantry> (gSpeisekammer, gZoneSwitch, gAllZones)
DateTime zSpeisekammerLastUpdate "Speisekammer - letzte Änderung [%s]" <time> (gSpeisekammer, gZoneLastUpdate)
Group gGarderobe "Garderobe - Gruppe" <status> (gZone)
Switch zGarderobe "Garderobe" <wardrobe> (gGarderobe, gZoneSwitch, gAllZones)
DateTime zGarderobeLastUpdate "Garderobe - letzte Änderung [%s]" <time> (gGarderobe, gZoneLastUpdate)
Group gWohnzimmer "Wohnzimmer - Gruppe" <status> (gZone)
Switch zWohnzimmer "Wohnzimmer" <sofa> (gWohnzimmer, gZoneSwitch, gAllZones)
DateTime zWohnzimmerLastUpdate "Wohnzimmer - letzte Änderung [%s]" <time> (gWohnzimmer, gZoneLastUpdate)
Group gFlur "Flur - Gruppe" <status> (gZone)
Switch zFlur "Flur" <corridor> (gFlur, gZoneSwitch, gAllZones)
DateTime zFlurLastUpdate "Flur - letzte Änderung [%s]" <time> (gFlur, gZoneLastUpdate)
Group gMalzimmer "Malzimmer - Gruppe" <status> (gZone)
Switch zMalzimmer "Malzimmer" <office> (gMalzimmer, gZoneSwitch, gAllZones)
DateTime zMalzimmerLastUpdate "Malzimmer - letzte Änderung [%s]" <time> (gMalzimmer, gZoneLastUpdate)
String zoneAction "Action" <fan> (gZoneControl)
the rules:
// ----------------------------------------------------------------------------
rule "zone control - zone selection"
// ----------------------------------------------------------------------------
when
Member of gZoneSwitch received update
then
logInfo("zone.rules", "update received from item: " + triggeringItem)
val zoneSwitch = triggeringItem as SwitchItem
val lastUpdate = now
zoneSwitch.getGroupNames().forEach[groupName |
if (groupName != "gZoneLastSwitch")
{
logDebug("zone.rules", "find related members of " + groupName + " in other group gZoneLastUpdate from triggering item " + triggeringItem.name)
gZoneLastUpdate.members.filter[updateItem | !updateItem.getGroupNames.contains(groupName)].forEach[ updateItem |
logInfo("zone.rules", "posting update to " + updateItem.name)
updateItem.postUpdate(lastUpdate.toString())
]
}
else
{
logDebug("zone.rules", "ignoring group " + groupName)
}
]
end
// ----------------------------------------------------------------------------
rule "zone control - action"
// ----------------------------------------------------------------------------
when
Item zoneAction received command
then
logInfo("zone.rules", "zoneAction command received: " + receivedCommand)
var StringBuilder zoneCmd = new StringBuilder
var StringBuilder roomCmd = new StringBuilder
// use this to get the room numbers
// actionCommand.sendCommand("get_room_mapping[]")
if (gAllZones.state == ON)
{
logInfo("zone.rules", "sending cmd to device: app_start")
actionCommand.sendCommand("app_start")
return;
}
// sort by timestamp and loop throug items
gZoneLastUpdate.members.sortBy[(state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli].forEach[zoneLastUpdateItem |
logDebug("zone.rules", "--> "+ zoneLastUpdateItem)
// loop until we find the right group...
zoneLastUpdateItem.getGroupNames().forEach[groupName |
logDebug("zone.rules", "----> "+ groupName)
if (groupName != "gZoneLastUpdate")
{
logDebug("zone.rules", "find related members of " + groupName + " in other group gZoneSwitch")
// find the switch item from the same room group
gZoneSwitch.members.filter[zoneSwitchItem |
zoneSwitchItem.getGroupNames.contains(groupName)
&& zoneSwitchItem.getGroupNames.contains("gZoneSwitch")].forEach[ zoneSwitchItem |
logDebug("zone.rules", "found related switch item " + zoneSwitchItem.name + " with state " + zoneSwitchItem.state)
if (zoneSwitchItem.state == ON)
{
var zoneType = transform("MAP", "robo_room_coordinates.map", zoneSwitchItem.name + "#type")
var zoneCoordinates = transform("MAP", "robo_room_coordinates.map", zoneSwitchItem.name + "#coordinates")
logInfo("zone.rules", zoneCoordinates + "-" + zoneSwitchItem.name + " is ON. {zoneType:" + zoneType + "; zoneCoordinates: " + zoneCoordinates + "}")
// not sure if we can assign a new var by reference, so to be safe, just use if..else and duplicate code
if (zoneType == "zone")
{
if (zoneCmd.length == 0)
{
zoneCmd.append("app_zoned_clean[")
}
zoneCmd.append(zoneCoordinates)
}
else if (zoneType == "room")
{
if (roomCmd.length == 0)
{
roomCmd.append("app_segment_clean[" + zoneCoordinates)
}
else
{
roomCmd.append(", " + zoneCoordinates)
}
}
logDebug("zone.rules", roomCmd.toString)
}
]
}
]
]
// if we have rooms AND zones, rooms wins - duplicate code here as well
if (roomCmd.length != 0)
{
val cmd = roomCmd.toString + "]"
logInfo("zone.rules", "sending cmd to device: " + cmd )
actionCommand.sendCommand(cmd)
}
else if (zoneCmd.length != 0)
{
val cmd = zoneCmd.toString + "]"
logInfo("zone.rules", "sending cmd to device: " + cmd )
actionCommand.sendCommand(cmd)
}
else
{
logInfo("zone.rules", "no zone or room selected. nothing to do.")
}
zoneAction.postUpdate("start")
end
// ----------------------------------------------------------------------------
rule "zone control - init"
// ----------------------------------------------------------------------------
when
System started
then
val lastUpdate = now
gZoneLastUpdate.members.forEach(item |
item.postUpdate(lastUpdate.toString())
)
end
the map:
zEsstisch#type=zone
zEsstisch#coordinates=[25500,32500,27000,30000,1]
zKueche#type=room
zKueche#coordinates=16
zToilette#type=room
zToilette#coordinates=17
zSpeisekammer#type=room
zSpeisekammer#coordinates=18
zGarderobe#type=room
zGarderobe#coordinates=19
zWohnzimmer#type=room
zWohnzimmer#coordinates=20
zFlur#type=room
zFlur#coordinates=21
zMalzimmer#type=room
zMalzimmer#coordinates=22
the sitemap
Frame label=Zonenreinigung
Switch item=gAllZones label="Komplettreinigung"
Default item=zEsstisch visibility=[gAllZones==OFF]
Default item=zKueche visibility=[gAllZones==OFF]
Default item=zToilette visibility=[gAllZones==OFF]
Default item=zSpeisekammer visibility=[gAllZones==OFF]
Default item=zGarderobe visibility=[gAllZones==OFF]
Default item=zWohnzimmer visibility=[gAllZones==OFF]
Default item=zFlur visibility=[gAllZones==OFF]
Default item=zMalzimmer visibility=[gAllZones==OFF]
Switch item=zoneAction label="Steuerung" mappings=[start="Start"]
Group item=gZoneLastUpdate label="Details"
Any feedback and improvments are welcome.
I am already looking forward for my next openHAB project