Skip to content
This repository has been archived by the owner on May 17, 2021. It is now read-only.

MiOS Binding Example

Mark edited this page Mar 22, 2015 · 16 revisions

MiOS Binding Example

This document is intended to provide MiOS Binding users with real-world example openHAB configurations.

Users typically have configurations falling into one or more of the following categories, which will be used to outline any subsequent examples:

  • Augmenting - openHAB Rules that "add" to existing MiOS Scenes.
  • Co-existing - Replacing MiOS Scenes with openHAB Rules, but keeping the Devices.
  • Replacing - wholesale replacement of MiOS functionality (Devices|Scenes) with openHAB equivalent functionality.

Examples for Augmenting

Adding Notifications and Text-to-Speech (TTS) when a House Alarm is triggered

MiOS has a standardized definition that most Alarm Panel plugins adhere to (DSC, Ademco, GE Caddx, Paradox, etc). This exposes a standardized UPnP-style attribute, AlarmPartition2/Alarm, for the Alarm System being in active Alarm mode. It has the value None or Alarm.

Here we check the specific transition between those two states as we want to avoid being re-notified, when the Uninitialized » Alarm state transition occurs, should openHAB restart.

Item declaration (house.items):

String   AlarmArea1Alarm "Alarm Area 1 Alarm [%s]" (GAlarmArea1) {mios="unit:house,device:228/service/AlarmPartition2/Alarm"}
String   AlarmArea1ArmMode "Alarm Area 1 Arm Mode [%s]" (GAlarmArea1) {mios="unit:house,device:228/service/AlarmPartition2/ArmMode"}
String   AlarmArea1LastUser "Alarm Area 1 Last User [%s]" (GAlarmArea1) {mios="unit:house,device:228/service/AlarmPartition2/LastUser"}

Rule declaration (house-alarm.rules):

rule "Alarm Panel Breach"
when
	Item AlarmArea1Alarm changed to Active
then
	var t = now

	pushNotification("House-Alarm", "House in ALARM!! Notification")
	say("Alert: House in Alarm Notification")

	var long x = now.getMillis - t.getMillis
	logInfo("house-alarm", "PERF Alarm-Panel-Breach elapsed: " + String::valueOf(x) + "ms")
end

rule "Alarm Panel Armed (Any)"
when
	Item AlarmArea1ArmMode changed from Disarmed to Armed
then
	var t = now

	say("Warning! House Armed Notification")

	// Perform deferred notifications, as the User.state may not have been processed yet.
	createTimer(now.plusSeconds(1)) [
		logDebug("house-alarm", "Alarm-Panel-Armed-Any Deferred notification")
		var user = AlarmArea1LastUser.state as StringType

		if (user == null) user = "user unknown"
		pushNotification("House-Armed", "House Armed Notification (" + user + ")")
	]

	var long x = now.getMillis - t.getMillis
	logInfo("house-alarm", "PERF Alarm-Panel-Armed-Any elapsed: " + String::valueOf(x) + "ms")
end

rule "Alarm Panel Disarmed (Fully)"
when
	Item AlarmArea1ArmMode changed from Armed to Disarmed
then
	var t = now

	say("Warning! House Disarmed Notification")

	// Perform deferred notifications, as the User.state may not have been processed yet. 
	createTimer(now.plusSeconds(1)) [
		logDebug("house-alarm", "Alarm-Panel-Disarmed-Fully Deferred notification")
		var user = AlarmArea1LastUser.state as StringType

		if (user == null) user = "user unknown"
		pushNotification("House-Disarmed", "House Disarmed Notification (" + user + ")")
	]

	var long x = now.getMillis - t.getMillis
	logInfo("house-alarm", "PERF Alarm-Panel-Disarmed-Fully elapsed: " + String::valueOf(x) + "ms")
end

Examples for Co-existing

When Motion detected turn Lights ON (OFF after 5 minutes)

This is typical of a declarative Scene in MiOS. In this case, the lights are left on for 5 minutes, and if new motion is detected in that time, another 5 minute clock is started.

The logging can be removed as needed.

Item declaration (house.items):

Group GSwitch All

Switch   MasterClosetLightsStatus "Master Closet Lights" (GSwitch) {mios="unit:house,device:391/service/SwitchPower1/Status"}
Switch   MasterClosetFibaroLightStatus "Master Closet Fibaro Light" (GSwitch) {mios="unit:house,device:431/service/SwitchPower1/Status"}

Rule declaration (house-master.rules):

import org.openhab.model.script.actions.Timer
import org.joda.time.*

val int DELAY_SECONDS = 300
var Timer mclTimer = null

rule "Master Closet Motion"
when
	Item MasterClosetZoneTripped changed from CLOSED to OPEN
then
	logInfo("house-master", "Master-Closet-Motion Timer lights ON")
	sendCommand(MasterClosetLightsStatus, ON)
	sendCommand(MasterClosetFibaroLightStatus, ON)

	if (mclTimer == null) {
		mclTimer = createTimer(now.plusSeconds(DELAY_SECONDS)) [
			mclTimer = null
			logInfo("house-master", "Master-Closet-Motion Timer lights OFF")
			sendCommand(MasterClosetLightsStatus, OFF)
			sendCommand(MasterClosetFibaroLightStatus, OFF)
		]
	} else {
		logInfo("house-master", "Master-Closet-Motion Timer extend")
		mclTimer.reschedule(now.plusSeconds(DELAY_SECONDS))
	}
end

When Motion detected turn Lights ON (if nighttime) and OFF after 5 minutes.

A variant of the above, this Rule has parts that only run at Nighttime. Here we use the Astro Binding to compute daylight hours. See the Astro Binding configuration for details on how to setup that Binding's configuration/openhab.cfg entry.

Item declaration (sunrise.items):

DateTime ClockDaylightStart "Daylight Start [%1$tH:%1$tM]" <calendar> {astro="planet=sun, type=daylight, property=start, offset=-30"}
DateTime ClockDaylightEnd   "Daylight End [%1$tH:%1$tM]" <calendar>   {astro="planet=sun, type=daylight, property=end, offset=+30"}

Item declaration (house.items):

Switch   KitchenSinkLightStatus "Kitchen Sink Light" (GSwitch) {mios="unit:house,device:99/service/SwitchPower1/Status"}
Switch   KitchenPantryLightStatus "Kitchen Pantry Light" (GSwitch) {mios="unit:house,device:425/service/SwitchPower1/Status"}
Switch   PowerHotWaterPumpStatus "Power Hot Water Pump" (GSwitch) {mios="unit:house,device:303/service/SwitchPower1/Status"}
Switch   KitchenPantryZoneArmed "Zone Armed [%s]" {mios="unit:house,device:426/service/SecuritySensor1/Armed"}

Rule declaration (house-kitchen.rules):

import org.openhab.core.library.types.*
import org.openhab.model.script.actions.Timer
import org.joda.time.*

val int DELAY_SECONDS = 240
var Timer kTimer = null

rule "Kitchen Motion"
when
        Item KitchenMotionZoneTripped changed from CLOSED to OPEN
then
        logInfo("house-kitchen", "Kitchen-Motion Timer ON")

        // Ignore this Rule if the Motion sensor is bypassed.
        if (KitchenMotionZoneArmed.state != ON) {
                logInfo("house-kitchen", "Kitchen-Motion Not Armed, skipping")
                return void
        }

        val DateTime daylightStart = new DateTime((ClockDaylightStart.state as DateTimeType).getCalendar)
        val DateTime daylightEnd = new DateTime((ClockDaylightEnd.state as DateTimeType).getCalendar)

        var boolean night = daylightStart.isAfterNow || daylightEnd.isBeforeNow

        if (night) {
                logInfo("house-kitchen", "Kitchen-Motion Night Time")
                sendCommand(KitchenSinkLightStatus, ON)
                sendCommand(KitchenPantryLightStatus, ON)
        }

        logInfo("house-kitchen", "Kitchen-Motion Any Time")
        sendCommand(PowerHotWaterPumpStatus, ON)

        if (kTimer == null) {
                kTimer = createTimer(now.plusSeconds(DELAY_SECONDS)) [
                        kTimer = null
                        logInfo("house-kitchen", "Kitchen-Motion Timer OFF")
                        sendCommand(KitchenSinkLightStatus, OFF)
                        sendCommand(KitchenPantryLightStatus, OFF)
                        sendCommand(PowerHotWaterPumpStatus, OFF)
                ]
        } else {
                logInfo("house-kitchen", "Kitchen-Motion Timer Extend")
                kTimer.reschedule(now.plusSeconds(DELAY_SECONDS))
        }
end

When opening/closing Windows keep Nest Away state in sync to save energy.

This originally ran as a Scene on the MiOS Unit, but was replaced with an openHAB Rule. The Items are a mix of Items, from an Alarm system running on MiOS, and the Nest Binding, running locally.

Explicitly check for the OPEN » CLOSED state transition, to avoid issues when openHAB restarts (Uninitialized » OPEN) or when duplicate values come in from the MiOS System (OPEN » OPEN).

Item declaration (house.items):

Group GPersist (All)
Group GWindow "All Windows [%d]" <contact> (GContact)

Contact  LivingRoomZoneTripped "Living Room (Zone 2) [MAP(en.map):%s]" <contact>        (GWindow,GPersist) {mios="unit:house,device:117/service/SecuritySensor1/Tripped"}
Contact  KitchenZoneTripped "Kitchen (Zone 3) [MAP(en.map):%s]" <contact>               (GWindow,GPersist) {mios="unit:house,device:118/service/SecuritySensor1/Tripped"}
Contact  FamilyRoomZoneTripped "Family Room (Zone 5) [MAP(en.map):%s]" <contact>        (GWindow,GPersist) {mios="unit:house,device:120/service/SecuritySensor1/Tripped"}
Contact  MasterBedroomZoneTripped "Master Bedroom (Zone 8) [MAP(en.map):%s]" <contact>  (GWindow,GPersist) {mios="unit:house,device:122/service/SecuritySensor1/Tripped"}
Contact  Bedroom3ZoneTripped "Bedroom #3 (Zone 9) [MAP(en.map):%s]" <contact>           (GWindow,GPersist) {mios="unit:house,device:123/service/SecuritySensor1/Tripped"}
Contact  Bedroom2ZoneTripped "Bedroom #2 (Zone 10) [MAP(en.map):%s]" <contact>          (GWindow,GPersist) {mios="unit:house,device:124/service/SecuritySensor1/Tripped"}
Contact  GuestBathZoneTripped "Guest Bathroom (Zone 11) [MAP(en.map):%s]" <contact>     (GWindow,GPersist) {mios="unit:house,device:125/service/SecuritySensor1/Tripped"}
Contact  StairsWindowsZoneTripped "Stairs Windows (Zone 12) [MAP(en.map):%s]" <contact> (GWindow,GPersist) {mios="unit:house,device:126/service/SecuritySensor1/Tripped"}
Contact  MasterBath1ZoneTripped "Master Bath (Zone 19) [MAP(en.map):%s]" <contact>      (GWindow,GPersist) {mios="unit:house,device:133/service/SecuritySensor1/Tripped"}
Contact  MasterBath2ZoneTripped "Master Bath (Zone 20) [MAP(en.map):%s]" <contact>      (GWindow,GPersist) {mios="unit:house,device:134/service/SecuritySensor1/Tripped"}
Contact  MasterBath3ZoneTripped "Master Bath (Zone 21) [MAP(en.map):%s]" <contact>      (GWindow,GPersist) {mios="unit:house,device:135/service/SecuritySensor1/Tripped"}

Rule declaration (house.rules):

rule "Windows Closed (all)
when
	Item Bedroom2ZoneTripped changed from OPEN to CLOSED or
	Item Bedroom3ZoneTripped changed from OPEN to CLOSED or
	Item FamilyRoomZoneTripped changed from OPEN to CLOSED or
	Item GuestBathZoneTripped changed from OPEN to CLOSED or
	Item KitchenZoneTripped changed from OPEN to CLOSED or
	Item LivingRoomZoneTripped changed from OPEN to CLOSED or
	Item MasterBath1ZoneTripped changed from OPEN to CLOSED or
	Item MasterBath2ZoneTripped changed from OPEN to CLOSED or
	Item MasterBath3ZoneTripped changed from OPEN to CLOSED or
	Item MasterBedroomZoneTripped changed from OPEN to CLOSED or
	Item StairsWindowsZoneTripped changed from OPEN to CLOSED
then
	if (GWindow.members.filter(s|s.state==OPEN).size == 0) {
		say("Attention: All Windows closed.")
		Nest_away.sendCommand("home")
	}
end

rule "Windows Opened (any)"
when
	Item Bedroom2ZoneTripped changed from CLOSED to OPEN or
	Item Bedroom3ZoneTripped changed from CLOSED to OPEN or
	Item FamilyRoomZoneTripped changed from CLOSED to OPEN or
	Item GuestBathZoneTripped changed from CLOSED to OPEN or
	Item KitchenZoneTripped changed from CLOSED to OPEN or
	Item LivingRoomZoneTripped changed from CLOSED to OPEN or
	Item MasterBath1ZoneTripped changed from CLOSED to OPEN or
	Item MasterBath2ZoneTripped changed from CLOSED to OPEN or
	Item MasterBath3ZoneTripped changed from CLOSED to OPEN or
	Item MasterBedroomZoneTripped changed from CLOSED to OPEN or
	Item StairsWindowsZoneTripped changed from CLOSED to OPEN
then
	if (GWindow.members.filter(s|s.state==OPEN).size == 1) {
		say("Attention: First Window opened.")
		Nest_away.sendCommand("away")
	}
end

Examples for Replacing

Publishing data to SmartEnergyGroups.com (SEG)

I wrote this script to publish data from MiOS to SmartEnergyGroups (SEG) for analysis.

Here's what you do to replace it with openHAB functionality:

Item declaration (house.items):

Group GPersist (All)

Group GMonitor (All)
Group GMonitorTemperature (GMonitor)
Group GMonitorHumidity (GMonitor)
Group GMonitorEnergy (GMonitor)

Number   WeatherTemperatureCurrentTemperature "Outside [%.1f °F]" <temperature>          (GPersist,GMonitorTemperature) {mios="unit:house,device:318/service/TemperatureSensor1/CurrentTemperature"}
Number   WeatherLowTemperatureCurrentTemperature "Outside Low [%.1f °F]" <temperature>   (GPersist,GMonitorTemperature) {mios="unit:house,device:319/service/TemperatureSensor1/CurrentTemperature"}
Number   WeatherHighTemperatureCurrentTemperature "Outside High [%.1f °F]" <temperature> (GPersist,GMonitorTemperature) {mios="unit:house,device:320/service/TemperatureSensor1/CurrentTemperature"}
Number   WeatherHumidityCurrentLevel "Outside Humidity [%d %%]"                          (GPersist,GMonitorHumidity)    {mios="unit:house,device:321/service/HumiditySensor1/CurrentLevel"}
Number   NestTStatUpstairs_humidity "Humidity [%d %%]"                                   (GPersist,GMonitorHumidity)    {nest="<[thermostats(Upstairs).humidity]"}
Number   NestTStatUpstairs_ambient_temperature_f "Upstairs [%.1f °F]" <temperature>      (GPersist,GMonitorTemperature) {nest="<[thermostats(Upstairs).ambient_temperature_f]"}
Number   NestTStatDownstairs_humidity "Humidity [%d %%]"                                 (GPersist,GMonitorHumidity)    {nest="<[thermostats(Downstairs).humidity]"}
Number   NestTStatDownstairs_ambient_temperature_f "Downstairs [%.1f °F]" <temperature>  (GPersist,GMonitorTemperature) {nest="<[thermostats(Downstairs).ambient_temperature_f]"}

Persistence declaration (rrd4j.persist):

Strategies {
	// for rrd charts, we need a cron strategy
	everyMinute : "0 * * * * ?"
	everyDay : "0 0 23 * * ?"
}

Items {
	SystemDataVersion, SystemUserDataDataVersion, SystemTimeStamp, SystemLocalTime, SystemLoadTime : strategy = everyDay
	GPersist* : strategy = everyChange, everyMinute, restoreOnStartup
	GTemperature* : strategy = everyMinute, restoreOnStartup
}

Rule declaration (seg.rules):

import org.openhab.core.library.types.*
import java.util.Locale

rule "Log Data to SmartEnergyGroups (SEG)"
when
	Time cron "0 0/2 * * * ?" or
	Item NestTStatUpstairs_ambient_temperature_f changed or
	Item NestTStatDownstairs_ambient_temperature_f changed or
	Item WeatherTemperatureCurrentTemperature changed or
	Item WeatherLowTemperatureCurrentTemperature changed or
	Item WeatherHighTemperatureCurrentTemperature changed or
	Item NestTStatUpstairs_humidity changed or
	Item NestTStatDownstairs_humidity changed or
	Item WeatherHumidityCurrentLevel changed
then
	val String SEG_SITE = "<yourSiteKeyHere>"
	val String SEG_URL = "http://api.smartenergygroups.com/api_sites/stream"
	val String NODE_NAME = "openHAB"
	val Locale LOCALE = Locale::getDefault

	var String segData = ""

	GMonitorTemperature?.members.forEach(item|
		segData = segData + String::format(LOCALE, "(t_%s %s)", item.name, (item.state as Number).toString)
	)

	GMonitorHumidity?.members.forEach(item |
		segData = segData + String::format(LOCALE, "(h_%s %s)", item.name, (item.state as Number).toString)
	)

	GMonitorEnergy?.members.forEach(item |
		segData = segData + String::format(LOCALE, "(e_%s %s)", item.name, (item.state as Number).toString)
	)

	segData = String::format("(site %s (node %s ? %s))", SEG_SITE, NODE_NAME, segData)
	sendHttpPostRequest(SEG_URL, "application/x-www-form-urlencoded", segData)
end

Installation


User Interfaces


Community

(link to openHAB forum)

Development



Misc


Samples

A good source of inspiration and tips from users gathered over the years. Be aware that things may have changed since they were written and some examples might not work correctly.

Please update the wiki if you do come across any out of date information.

Use case examples

Collections of Rules on a single page

Single Rules

Scripts


Release Notes

Clone this wiki locally