Startseite » künstlicher Sonnenaufgang mit OpenHAB, Kalender und Hue

künstlicher Sonnenaufgang mit OpenHAB, Kalender und Hue

Morgens von langsam aufdimmenden Licht geweckt zu werden, unterstützt deinen Prozess in den Tag zu starten. Mit einer Smart-Blub wie Phillips Hue lässt sich das leicht bewerkstelligen. Ich steuere dieses Ereignis darüber hinaus mit meinem Google Kalender um sich verändernde Verhältnisse einfach abzubilden.

Kalender-Item

Den Kalender richte ich mittels des OpenHAB ical-Moduls ein. Die zugehörigen Items sehen so aus:

Group:Switch:COUNT(ON)		igCalWaking										"Weckprofil"						(sgBedroom)["WebService"]
Switch				KalenderWecken_CurrentEventPresence						"Current Event Presence"			(igCalWaking)												{ channel="icalendar:calendar:Wecken:current_presence" }
String				KalenderWecken_CurrentEventTitle						"Current Event Title"				(igCalWaking)												{ channel="icalendar:calendar:Wecken:current_title" }
DateTime			KalenderWecken_CurrentEventStart						"Current Event Start"				(igCalWaking)												{ channel="icalendar:calendar:Wecken:current_start" }
DateTime			KalenderWecken_CurrentEventEnd							"Current Event End"					(igCalWaking)												{ channel="icalendar:calendar:Wecken:current_end" }

Smart-Bulb-Item

In meinem Fall verwende ich Phillips Hue zusammen mit zigbee2mqtt.

//		Schlafzimmer
Group  		igSchlafzimmerLight        			"Schlafzimmer"          		      				(sgBedroom)["Lightbulb", "Group"]									
Color		SchlafzimmerRoom_Farbe				"Farbe"						<ColorLight>			(igSchlafzimmerLight,sgBedroom,tgLSchange)["Control", "Light"]						{ autoupdate="false", channel="mqtt:topic:myMosquitto:HueBulbBedRoom:color", alexa="Color" }
Dimmer		SchlafzimmerRoom_Farbtemperatur		"Farbtemperatur"			<ColorLight>			(igSchlafzimmerLight,tgLSinterrupt,sgBedroom)["Control", "ColorTemperature"]		{ autoupdate="false", channel="mqtt:topic:myMosquitto:HueBulbBedRoom:color_temperature", alexa="ColorTemperature" }
Dimmer		SchlafzimmerRoom_Helligkeit			"Licht"						<DimmableLight>			(igSchlafzimmerLight,tgLSinterrupt,sgBedroom)["Control", "Brightness"]				{ autoupdate="false", channel="mqtt:topic:myMosquitto:HueBulbBedRoom:brightness", alexa="Brightness,PowerState" }
String		SchlafzimmerRoom_Lightshow			"Lightshow"											(igSchlafzimmerLight,tgLightshow,sgBedroom)["Control", "DynamicScene"]				{ alexa="Mode" [capabilityNames="@Setting.Mode",supportedModes="Normal,Kerzenlicht,Polarlicht,Farbwechsel,Zufallsfarben,Gewitter,TV-Simulation"] }
Dimmer		SchlafzimmerRoom_LightshowSpeed		"Geschwindigkeit"									(igSchlafzimmerLight,sgBedroom)["Control", "DynamicSpeed"]							{ alexa="RangeValue" [capabilityNames="Geschwindigkeit,Speed", supportedRange="0:100:10", presets="10=@Value.Low:@Value.Minimum,50=@Value.Medium:Normal,100=@Value.High:@Value.Maximum"] }
String		SchlafzimmerRoom_Interface			"Interface"											(igSchlafzimmerLight)["Control", "Interface"]										{ channel="mqtt:topic:myMosquitto:HueBulbBedRoom:interface" }

Sonnenaufgang-Rule

Die Folgende Regel vollführt den Trick. Dabei greife ich auf eine mathematische Lösung zurück. Das Licht wird über einen bestimmten Zeitraum bis zu einem maximalen Wert aufgedimmt. Alle Schritte dazwischen werden berechnet. Wenn der aktuelle Status zu weit von dem durch dieses System berechneten Status abweicht, wird nicht weiter damit fortgefahren. Dadurch kann der Vorgang manuell durch Ein- oder Ausschalten abgebrochen werden.

/etc/openhab/rules/bedroom-wakeup-light.rules

val int stepTime = 2 //minutes
val int sunriseTime = 30 //minutes
val int maxValue = 60 //%


rule "Wochenprofile ein math"
when
	Time cron "0 0/2 * * * ?"
then {
	if(KalenderWecken_CurrentEventStart.state != UNDEF){
		val eventStarted = (KalenderWecken_CurrentEventStart.state as DateTimeType).getZonedDateTime()
		var double diffSec = (now.toInstant().toEpochMilli() - eventStarted.toInstant().toEpochMilli())/1000
		var double diffMin = diffSec/60
		var double stepPerMin = maxValue/sunriseTime
		
		//Soll-Wert zu dem Zeitpunk
		var double setpoint = diffMin * stepPerMin
		if(setpoint > maxValue){
			setpoint = maxValue
		}
		
		//Untergrenze des Sollwertes
		var double setpointLow = (diffMin - stepTime) * stepPerMin
		if(setpointLow < 0){
			setpointLow = 0
		}
		
		var e = SchlafzimmerBg_Helligkeit
		var actualValue = (e.state as DecimalType).intValue
		
		if(
			actualValue >= setpointLow &&
			actualValue < setpoint
		){
			e.sendCommand(setpoint)
		}
	}
}
end

rule "Wochenprofile aus"
when
	Item KalenderWecken_CurrentEventPresence changed to OFF
then {
	SchlafzimmerRoom_Helligkeit.sendCommand(0)
}
end

/**
 * Weekly Profiles / Wake-up Light Automation
 */
const { rules, triggers, items, time } = require("openhab");

// Configuration
const STEP_TIME = 2;        // Minutes (Tolerance window for manual intervention)
const SUNRISE_TIME = 30;    // Minutes (Total duration of the fade-in process)
const MAX_VALUE = 60;       // % (Maximum brightness target)

rules.JSRule({
  name: "Weekly Profile Sunrise Math",
  description: "Calculates brightness based on calendar event (sunrise simulation)",
  triggers: [triggers.GenericCronTrigger("0 0/2 * * * ?")], // Every 2 minutes
  execute: (event) => {
    const startItem = items.getItem("KalenderWecken_CurrentEventStart");
    
    // Check if a valid start time is set
    if (startItem.state === "NULL" || startItem.state === "UNDEF") {
      return;
    }

    // Time Calculation
    // time.toZDT() automatically uses the system timezone and parses the item state string
    const now = time.toZDT();
    const eventStarted = time.toZDT(startItem.state);

    // Calculate time difference
    // Using epoch milliseconds to determine the elapsed time since the event started
    const diffMillis = now.toInstant().toEpochMilli() - eventStarted.toInstant().toEpochMilli();
    const diffSec = diffMillis / 1000.0;
    const diffMin = diffSec / 60.0;

    // Calculate the slope (dimming rate)
    const stepPerMin = MAX_VALUE / SUNRISE_TIME;

    // Calculate the target setpoint
    let setpoint = diffMin * stepPerMin;
    if (setpoint > MAX_VALUE) {
      setpoint = MAX_VALUE;
    }

    // Calculate the lower bound (tolerance threshold)
    let setpointLow = (diffMin - STEP_TIME) * stepPerMin;
    if (setpointLow < 0) {
      setpointLow = 0;
    }

    // Get current light status
    const lightItem = items.getItem("SchlafzimmerRoom_Helligkeit");
    let actualValue = parseFloat(lightItem.state);
    
    // Default to 0 if the light is off or the state is unknown
    if (isNaN(actualValue)) { 
        actualValue = 0; 
    }

    // Logic Check
    // Only send a command if the current brightness is below the calculated setpoint 
    // but still above the lower threshold. This prevents the automation from 
    // dimming the light back down if it was manually set to a higher value (e.g., 100%).
    if (actualValue >= setpointLow && actualValue < setpoint) {
      // Use Math.round for clean integer values when sending the command
      lightItem.sendCommand(Math.round(setpoint).toString());
    }
  }
});

rules.JSRule({
  name: "Weekly Profile Off",
  description: "Turns off the light when the calendar event ends",
  triggers: [triggers.ItemStateChangeTrigger("KalenderWecken_CurrentEventPresence", null, "OFF")],
  execute: (event) => {
    items.getItem("SchlafzimmerRoom_Helligkeit").sendCommand("0");
  }
});

0
0

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden.

Translate »