Creative solutions or implementations using the NikoHome binding

I am starting this topic to have users from the NikoHome binding share some creative implementations with the binding. This should not be restricted to the Niko system setup but can also be using other bindings or solutions in combination. The objective is to share and inspire people.

Discussion about the binding and issues are here

Try to describe clearly the problem statement and the solution as well as post all relevant code.

3 Likes

Problem Statement: When renovating the house we installed a ventilator that will suck out the air in the ‘wet rooms’ such as toilet and bathroom. Type C for people that live in Belgium. The ventilator i had install was a simple 3 wire ventilator with the purpose of automating it based in air quality instead of keeping it always on. With the niko system I could not automate it more than turn it on or off with a button. The issue I have is that the below bathroom is not connected to the niko system so people would forget to turn it on when taking a bath.

Solution: I purchased 2 xiaomi humidity sensors and the bridge via the usual Chinese marketplace (no adds) that would measure the humidity in the bathroom. If the humidity goes above a threshold than the fan would activate itself. If the humidity dropped again it would deactivate itself. When a user manually set the ventilator to on the above logic would not interfere and disable the ventilator (it would stay forced on until manually disabled)

Code:
Niko.items note that i use the homekit binding which defines the [Switchable]

Switch        Ventilator         "Ventilator"                  [ "Switchable" ]    {channel="nikohomecontrol:onOff:440e003a366a:44:switch"}

Xianomi.i tems

// Xiaomi Temperature and Humidity Sensor
Number B1_Temperature "Badkamer Beneden [%.1f °C]"      <temperature> [ "CurrentTemperature" ] { channel="mihome:sensor_ht:158d00020ef1cb:temperature" }
Number B1_Humidity    "Badkamer Beneden [%.1f %%]"       <humidity>    [ "CurrentHumidity" ]    { channel="mihome:sensor_ht:158d00020ef1cb:humidity" }
Number B1_Battery                                     <battery>                              { channel="mihome:sensor_ht:158d00020ef1cb:batteryLevel" }
Switch B1_BatteryLow                                  <energy>                               { channel="mihome:sensor_ht:158d00020ef1cb:lowBattery" }
Number B2_Temperature "Badkamer Boven [%.1f °C]"        <temperature> [ "CurrentTemperature" ] { channel="mihome:sensor_ht:158d0001e878ef:temperature" }
Number B2_Humidity    "Badkamer Boven [%.1f %%]"          <humidity>    [ "CurrentHumidity" ]    { channel="mihome:sensor_ht:158d0001e878ef:humidity" }
Number B2_Battery                                     <battery>                              { channel="mihome:sensor_ht:158d0001e878ef:batteryLevel" }
Switch B2_BatteryLow                                  <energy>                               { channel="mihome:sensor_ht:158d0001e878ef:lowBattery" }

Switch vFan1           "Vochtig Beneden"   // Ventilator aan door vochtigheid
Switch vFan2           "Vochtig Boven"   // Ventilator aan door vochtigheid
// ------------------------SET FAN BY HUMIDITY

rule "MANAGE FAN B1"
when
    Item B1_Humidity changed
then
    if (B1_Humidity.state >= 55) {// changed to >= so 55 wouldn't be left out
        if (Ventilator.state == OFF) {
            sendCommand(vFan1,ON)
            sendCommand(Ventilator,ON)
            logInfo("logFan", "Hoge Vochtigheid Beneden, zet ventilator aan.")
        }
    }
    else {
        if (Ventilator.state == ON && vFan1.state == ON && B1_Humidity.state < 54) {
            sendCommand(Ventilator,OFF)
            sendCommand(vFan1,OFF)     
            logInfo("logFan", "Lage Vochtigheid B1, zet ventilator uit.")
        }
    }
end

rule "MANAGE FAN B2"
when
    Item B2_Humidity changed
then
    if (B2_Humidity.state >= 55) {// changed to >= so 55 wouldn't be left out
        if (Ventilator.state == OFF) {
            sendCommand(vFan2,ON)
            sendCommand(Ventilator,ON)
            logInfo("logFan", "Hoge Vochtigheid Boven, zet ventilator aan.")
        }
    }
    else {
        if (Ventilator.state == ON && vFan2.state == ON && B2_Humidity.state < 54) {
            sendCommand(Ventilator,OFF)
            sendCommand(vFan2,OFF)     
            logInfo("logFan", "Lage Vochtigheid Boven, zet ventilator uit.")
        }
    }
end

Problem Statement: I wanted to turn on the LED that I have embedded in a glass railing on the first floor based upon the ‘night time’ as it is also a night light for the kids when they need to go to the toilet. As the night time is different in winter and summer I did not want a simple timer but something more sophisticated.

Solution: I installed the astro binding which allows me to determine if it is night or day and setup some simple rules. Now the LED go on when the sun goes down and vice versa.

You can use this logic for outside items and avoid buying a 350-10032 switch. If you want you can modify so it takes into account an offset to activate the switch before or after sunset/down.

Niko.items note that i use the homekit binding which defines the [“Lighting”]

Switch        Led             "Overloop Led"              <light> [ "Lighting" ]      {channel="nikohomecontrol:onOff:440e003a366a:26:switch"}

astro.items

// Astro

DateTime SunsetTime          "Sunset [%1$tH:%1$tM]"   <sun> (Astro) { channel="astro:sun:home:set#start" }
DateTime SunriseTime         "Sunrise [%1$tH:%1$tM]"  <sun> (Astro) { channel="astro:sun:home:rise#end" }
Number   SunElevation        "Elevation [%.1f °]"    <sun>  (Astro) { channel="astro:sun:home:position#elevation" }
Switch   NightState          "Night"
Switch	 Daylight	     "Daylight"

astro.rules

// ------------------------CONTROL DAYLIGHT
rule "OpenHAB system started - astro"
when
    System started
then
    createTimer(now.plusSeconds(180)) [ |
        if (now.isAfter((SunsetTime.state as DateTimeType).calendar.timeInMillis) ||
            now.isBefore((SunriseTime.state as DateTimeType).calendar.timeInMillis)
        ) {
            postUpdate(NightState, ON)
        } else {
            postUpdate(NightState, OFF)
        }
    ]
end

rule "Update NightState"
when
    Item SunElevation changed
then
    if(SunElevation.state >  0){
        if(NightState.state != OFF) postUpdate(NightState, OFF)
    } else {
        if(NightState.state != ON) postUpdate(NightState, ON)
    }
end

ledlight.rules

// ------------------------SET LED BY DAYLIGHT

rule "TURN ON LED Overloop"
when 
     Item NightState changed from OFF to ON
then
     {sendCommand(Led,ON)}
end

rule "TURN OFF LED Overloop"
when 
     Item NightState changed from ON to OFF
then
     {sendCommand(Led,OFF)}
end

I have a scene in NHC which I enable every morning when I go downstairs. This scene turns on some lights downstairs. I created a rule in OpenHAB so my Onkyo receiver turns on and puts on Radio (via Harmony).

rule "poweron Radio when NHC_gelijkvloers_ochtend is activated"
when
    Item NHC_gelijkvloers_ochtend changed from OFF to ON
then
    var Number hour = now.getHourOfDay
    logInfo("NHC_gelijkvloers","Hour: " + hour)
    if ((hour >= 5) && (hour <= 11)) {
        if (Harmony_Activity.state == "PowerOff") {
            Harmony_Activity.sendCommand("Radio")
        }
        Thread::sleep(2000)
        NHC_zithoek.sendCommand(78)
    }
end

Building on @extric99 type of scenario.
I build rules to automatically switch off lights when it is light enough. I have kids that would leave lights on all day otherwise :grinning:. The basic rule for that is based on the astro binding (like @extric99). However, I realised I also have solar panels on my roof that tell me when the sun is shining enough already, so I created a second rule that will switch off lights earlier if it makes sense. Again, this replaces an outside light detector.
The item PVPowerGS2 has the current power from one of my solar invertors. I use SBFspot to get that value every 15’. That is another topic what to use would depend on your solar setup. The principle should still apply.

var Timer tIndoorLights = null
val indoorDelay = 90
val minSunPower = 75

rule "Dim indoor lights"
when
	Channel 'astro:sun:local:rise#event' triggered START
then
	logInfo("sunrise.rules", "Dim indoor lights")
	
    logDebug("sunrise.rules", "Sunrise time = {}", Sunrise_Time.state)
	var DateTime sunrise = parse(Sunrise_Time.state.toString)

	// Schedule to turn all indoor lights off 'indoorDelay' minutes after sunrise
    // Cancel timer to avoid reschedule
    if(tIndoorLights !== null) {
        logDebug("sunrise.rules", "Timer tIndoorLights cancelled") 
        tIndoorLights.cancel()
        tIndoorLights = null
    }
    logDebug("sunrise.rules","Timer tIndoorLights created for {}", sunrise.plusMinutes(indoorDelay)) 
    tIndoorLights = createTimer(sunrise.plusMinutes(indoorDelay)) [|
	    logInfo("sunrise.rules", "Timer tIndoorLights (sunrise + {}) executed", indoorDelay) 
	    gLichten.send(OFF)
    ]
end

rule "Dim indoor lights on clear sky"
when
	Item PVPowerGS2 changed
then
	logInfo("sunrise.rules", "Dim indoor lights on clear sky")
	
	// It is light enough and the indoor lights turn off timer is running, so we can turn off earlier
	if ((PVPowerGS2.state > minSunPower) && (tIndoorLights !== null)) {
	    logDebug("sunrise.rules", "Minimum sunpower {}", minSunPower)
	    logDebug("sunrise.rules", "Current sunpower {}", PVPowerGS2.state)
        logDebug("sunrise.rules", "Timer tIndoorLights cancelled") 
        tIndoorLights.cancel()
        tIndoorLights = null
	    logInfo("sunrise.rules", "Lights turned off because it is light enough already") 
	    gLichten.send(OFF)			
	}
end

Problem: presence simulation dependent on season. In Niko Home Control, you either need an light detector, or a complex conditions table of day time and seasonality to make presence simulation work with different timing depending on the season. Often, you will actually need both. Conditions tables with more then 3 lines quickly become very cumbersome.
To avoid this complex conditions table, I defined one virtual switch in Niko Home Control (Status_Duister) which I update only from openHAB. When I now switch on presence simulation, it will consider this virtual switch. For details on how to configure presence simulation in Niko Home Control, see the Niko Home Control programmers guide.
Here is the openHAB ruleset:

rule "Daylight start"
when
	Channel 'astro:sun:local:daylight#event' triggered START
then
	logInfo("sunrise.rules", "Daylight start")
	
	DayLight.postUpdate(OPEN)
	// Turn off switch in Niko Home Control for presence simulation
	Status_Duister.sendCommand(OFF)
end

rule "Daylight end"
when
	Channel 'astro:sun:local:daylight#event' triggered END
then
	logInfo("sunrise.rules", "Daylight end")
	
	DayLight.postUpdate(CLOSED)
	// Set switch in Niko Home Control for presence simulation at night, but not after bedtime
	if (now.getMinuteOfDay() < (23 * 60 + 10)) {
		Status_Duister.sendCommand(ON)
	}
end

rule "Bedtime"
when
	Time cron "0 10 23 * * ?"
then
	logInfo("sunrise.rules", "Bedtime")
	
	// Turn off switch in Niko Home Control for presence simulation at bedtime
	Status_Duister.sendCommand(OFF)
end

rule "Wakeuptime"
when
	Time cron "0 15 7 * * ?"
then
	logInfo("sunrise.rules", "Wakeuptime")
	
	// Set switch in Niko Home Control for presence simulation in the morning, but not if already light
	if (DayLight.state == CLOSED) {
		Status_Duister.sendCommand(ON)
	}
end

The conditions table for the presence simulation activity in Niko Home Control then becomes:
image
where Is het duister ? = aan is a virtual output set by the Status_Duister action made visible to openHAB. 2 other 2 virtual outputs are the standard ones needed as described in the Niko Home Control programmer examples documentation.

Problem: switch on a few lights when TV is paused/stopped and dim again when continuing watching.
I am using NEEO as a remote for my TV/audio equipment. Thanks to @tmrobert8 excellent binding (see forum), I can now do that automatically when I push play/pause buttons.
Something similar should be possible with a Harmony.

I have one item Scene_TV that is made visible as a switch on my NEEO remote, using the NEEO transport from @tmrobert8. I currently switch on the scene manually. This could of course be automated.

Here is the rule to make this work:

rule "NEEO"
    when
        Channel 'neeo:brain:d487672e:forwardActions' triggered
    then
        var data = receivedEvent.getEvent()
 
        logInfo("neeo", "action received: {}", data)

        var String action = transform("JSONPATH", "$.action", data)
        var String device = transform("JSONPATH", "$.device", data)
        var String room = transform("JSONPATH", "$.room", data)
        var String actionparameter = transform("JSONPATH", "$.actionparameter", data)
        
        logDebug("neeo", "action: {}, device: {}, room: {}, actionparameter: {}", action, device, room, actionparameter)

        if (((device == "TV") || (device == "Blu-ray") || (device == "Mediaplayer")) && (Scene_TV.state == ON)) {
            if (action == "PLAY") {
                Licht_Zithoek_Staanlamp.postUpdate(ON)
                Licht_Zithoek.postUpdate(20)
            } else if ((action == "STOP") || (action == "PAUSE")) {
                Licht_Zithoek.postUpdate(70)
            }
            return
        }
end

Another interesting idea is from @philippaertske. He came up with a way to assign multiple function to one Niko Home Control button here.