One click wakeup alarm in music with LMS
Posted: Wednesday 03 February 2021 22:32
Hi all,
I made a DzVents script to wakeup with a Logitech Media Player. I wanted something simple to use and easy for changing the wake-up hour, and without any calendar.
Why Domoticz and not LMS GUI directly?!?
I've been using LMS GUI for years but I could not get what I wanted: a specific alarm routine: music in random at low level for 5 minutes, radio not random at normal level for 30 minutes, music in random at low level for 40 minutes. I should be up not too late after the radio slot
and have music on when I come back after breakfast...
This sequence was not possible with LMS, probably due to bugs, I could not start with music and after have radio, the music never stop at the end, not possible to have different levels on each slot. And also sometimes no wake up
So I did it why Domoticz.
I’d like to share it for the ones who want to use it, and to get feedback on the way I did it, it as I’m not a coder.
The GUI is a simple selector This part could be improved, but I know nothing with GUI and html…
The prerequisite is to have a Logitech Media Server, a player and the integration in Domoticz with the plugin Logitech Media Server.
The script is
updated on 06/02/2021 13:35 to fix an error (05/02/2021 in the script)
updated on 08/02/2021 fix the logging and an error due to new dz version
The configuration is done with variables explained in the script
I comment the following ones:
There is also a fallback possibility is case the LMS doesn’t play ; I blink a light (ERR_IDX)
If Domoticz missed the wakeup time (for some cause), when Domoticz could do something after, it will play the LMS.
As all the wanted methods for the LMS doesn’t exist in DzVents, I used direct api and so I need 2 sort of id for the LMS
local LMS_player= "b8:27:eb:7d:00:36" -- LMS Player MAC Address for json commands
local LMS_serverPort='erato:9000' -- LMS Server Hostname and HTTP Port Number
It is a morning wakeup alarm ; I’m not sure it works to wake up after noon
Next steps
Better widget?
More configuration via GUI rather than in the script…
Build a device like Oregon Projection Clocks to display if there an alarm on and other info from Domoticz like temperature… But I didn’t find anything regarding the projector…
Disclaimer: I'm not responsible if you don't wake up on time to "go" to work
I made a DzVents script to wakeup with a Logitech Media Player. I wanted something simple to use and easy for changing the wake-up hour, and without any calendar.
Why Domoticz and not LMS GUI directly?!?
I've been using LMS GUI for years but I could not get what I wanted: a specific alarm routine: music in random at low level for 5 minutes, radio not random at normal level for 30 minutes, music in random at low level for 40 minutes. I should be up not too late after the radio slot
This sequence was not possible with LMS, probably due to bugs, I could not start with music and after have radio, the music never stop at the end, not possible to have different levels on each slot. And also sometimes no wake up
So I did it why Domoticz.
I’d like to share it for the ones who want to use it, and to get feedback on the way I did it, it as I’m not a coder.
The GUI is a simple selector This part could be improved, but I know nothing with GUI and html…
The prerequisite is to have a Logitech Media Server, a player and the integration in Domoticz with the plugin Logitech Media Server.
The script is
Code: Select all
--[[
A one-click alarm to wake-up with the music off your Logitech Media Server (LMS).
Your can have several playlists played for the wakeup (music random, radio, other music random)
and with different level for each slot.
You can pause for one day ; there is also a vacation mode
When a playlist is send, there are some check that it is playing for real to be sure to wake up
If problem there is a fallback mode (for me blink my light)
If domoticz was down a the alarm time, the alarm is triggered when domoticz is back
About LMS API: http://tutoriels.domotique-store.fr/content/54/95/fr/api-logitech-squeezebox-server-_-player-http.html
Prerequisite: V2020.2 build 12924 (or from dzVents V 3.0.2 to domoticz 2020.2 build 12819)
hestia 29/05/2020> go live
hestia 28/10/2020> fix error when calling Blink (for fallback mode)
hestia 05/02/2021> move CheckResponse after PlayingKO to avoid error
hestia 07/02/2021> fix some issues with logging
hestia 08/02/2021> add some afterSec(x) on the OpenUrlLMS to avoid some risks of mix in calls
due to openURL optimisation #4585 (http requests on seperate threads dzVents)
--]]
local alarmStartPerDay = {'Pause', '6h40', '6h40', '6h40', '6h40', '6h40', '7h15'} -- to be present in WAKEUPTIME_IDX /!\ 1 is Sunday
local alarmDurations = {5, 30, 40, 0} -- alarm duration for each slot - 0 to stop the last alarm
local alarmPlayLists = {"zzReveilMusic","zzReveilInfo", "zzReveilDeezer"} -- playlists names for each slot /!\ no blank nor é à ...
local alarmLevels = {60, 77, 60} -- alarm level for each playlist
local alarmShuffle = {true, false, true} -- to shuffe or not each alarm slot
local userDayNames = {'Dim.', 'Lun.', 'Mar.', 'Mer.', 'Jeu.', 'Ven.', 'Sam.'} -- to change from dz config, to comment if not necessary
--local FAKE_LMS = 1037 -- to uncomment for testing
--local DUMMY = true -- to set to true for testing only w/o playing for real
local PLAYER_IDX = 1303 -- LMS player idx for dzVent commands
local LMS_player= "b8:27:eb:7d:00:36" -- LMS Player MAC Address for json commands
local LMS_serverPort='erato:9000' -- LMS Server Hostname and HTTP Port Number
local LMS_playlistsFolder="/media/playlists/" -- LMS Playlists Folder
local ERR_IDX = 967 -- backup device to use in case of issue with LMS
local ICON_ON = 237
local ICON_PLAY = 236
local ICON_OFF = 238
local ICON_PAUSE = 239
local WAKEUPTIME_IDX = 1035 -- dummy device to create with the wakeup times
local WAKEUPTIME_NAME = 'Réveil' -- inital name of the dummy device to create with the wakeup times
-- switch type selector, with level name like 6h30 6h35 6h40... and 'Pause' and 'Stop' (see param for value below
local alarmPauseValue = 'Pause' -- the value choosen to have the alarm off for 1 day
local alarmOffValue = 'Stop' -- the value choosen to have the alarm off
-- user variables to declare
local alarmStatus_idx=8
local alarmDate_idx =7
local alarmTime_idx =9
local alarmIndex_idx =10
local CALLBACKPREFIX=WAKEUPTIME_IDX -- if several instances of the script
local HHMM_SEPARATOR='h'
local TIME_DELAY=15
return {
logging = {
level =
domoticz.LOG_ERROR, --select one to override system log level normal = LOG_ERROR
--domoticz.LOG_DEBUG,
--domoticz.LOG_INFO,
--domoticz.LOG_ERROR,
--domoticz.LOG_FORCE
},
on = {
timer = {function(dz)
if dz.time.rawDate == dz.variables(alarmDate_idx ).date.rawDate then
if dz.time.matchesRule('at ' .. dz.variables(alarmTime_idx).value) then -- check exact minutes
--print('Exact time checked ' .. dz.variables(alarmTime_idx).value)
return true
else -- check if the time was missed
local maxTime= dz.variables(alarmTime_idx).time.addMinutes(TIME_DELAY)
local checkTime=dz.time.matchesRule('between ' .. dz.variables(alarmTime_idx).time.hour .. ":" .. dz.variables(alarmTime_idx).time.minutes
.. ' and ' .. maxTime.hour .. ":" .. maxTime.minutes)
--print('alarmTime ' .. dz.variables(alarmTime_idx).time.hour .. ":" .. dz.variables(alarmTime_idx).time.minutes)
--print('maxTime ' .. maxTime.hour .. ':' .. maxTime.minutes, dz.LOG_DEBUG)
if checkTime and dz.variables(alarmStatus_idx).value ~= 'PLAY' then -- the time was missed, no alarm triggered!
print('Alarm missed ' .. dz.variables(alarmTime_idx).value)
return true
else
--print('Alarm not missed')
end
end
else
--print('NOT today')
end
return false
end
},
devices = {
WAKEUPTIME_IDX
},
httpResponses = {
CALLBACKPREFIX..'LMS_Play',
CALLBACKPREFIX..'LMS_Shuffle',
CALLBACKPREFIX..'LMS_Unshuf',
CALLBACKPREFIX..'LMS_Status'
}
},
execute = function(dz, item, triggerInfo)
_G.logMarker = dz.moduleLabel -- set logmarker to scriptname
local LOG_LEVEL = dz.LOG_INFO -- normal
--local LOG_LEVEL = dz.LOG_DEBUG
--local LOG_LEVEL = dz.LOG_ERROR
--local LOG_LEVEL = dz.LOG_FORCE
dz.log('==>> triggered by ' .. triggerInfo.type, LOG_LEVEL)
local scriptRC=0 -- global retrun code to stop the scrip
local wakeupTimeBool=false
local wakeUpTime
local devPLAYER_IDX = dz.devices(PLAYER_IDX)
local devWAKEUPTIME = dz.devices(WAKEUPTIME_IDX)
local alarmStatus
local alarmDate
local alarmTime
local alarmIndex
local alarmValue
-----< BEG FUNCTIONS > ----------------------------------------------------------------------------------------
local function OpenUrlLMS (urlParams, urlCallback, p_afterSec)
-- open the player url with a callback to check the return code and player status
local httpLMS='http://'..LMS_serverPort..'/status.html?'
dz.openURL({url = httpLMS .. urlParams, callback = CALLBACKPREFIX..urlCallback}).afterSec(p_afterSec)
dz.log(urlCallback .. ' - ' .. urlParams, LOG_LEVEL)
return
end
local function PlayLMS(cmd, volume, playlist, shuffle)
-- cmd='On' => play the playlist with the volune and shuffle or not / "Off" => switch off the player
if cmd == 'On' then
dz.log('PlayLMS ' .. cmd .. ' ' .. volume .. ' ' .. playlist, LOG_LEVEL)
-- set the player w or w/o shuffle
local paramShuffle=0
if shuffle then paramShuffle=1 end
local shufflePlaylist='p0=playlist&p1=shuffle&p2='.. paramShuffle ..'&player='..LMS_player
-- adjust the volume
if DUMMY then
dz.log('DUMMY', LOG_LEVEL)
else
OpenUrlLMS(shufflePlaylist, 'LMS_Shuffle', 0)
devPLAYER_IDX.setVolume(volume).afterSec(1)
-- play the playlist
local playPlaylist='p0=playlist&p1=play&p2='..LMS_playlistsFolder..playlist..'.m3u&p3=1&player='..LMS_player
OpenUrlLMS(playPlaylist, 'LMS_Play', 2)
-- check the status, is the player playing? result in the callback...
local playStatus='&player='..LMS_player
OpenUrlLMS(playStatus, 'LMS_Status', 3)
end
if FAKE_LMS ~= nil then -- dummy to test the script w/o activate LMS
dz.log('==>> FAKE_LMS ' .. FAKE_LMS .. ' ' .. cmd, LOG_LEVEL)
dz.devices(FAKE_LMS).updateAlertSensor(dz.ALERTLEVEL_GREEN, playlist)
end
else
dz.log('PlayLMS ' .. cmd, LOG_LEVEL)
-- Stop, Unshuffle Playlist and SwitchOff
if DUMMY then
dz.log('DUMMY', LOG_LEVEL)
else
devPLAYER_IDX.stop()
local paramShuffle=0
local shufflePlaylist='p0=playlist&p1=shuffle&p2='.. paramShuffle ..'&player='..LMS_player
OpenUrlLMS(shufflePlaylist, 'LMS_Unshuf', 1)
devPLAYER_IDX.switchOff().afterSec(2)
end
if FAKE_LMS ~= nil then -- dummy to test the script w/o activate LMS
dz.log('==>> FAKE_LMS ' .. FAKE_LMS .. ' ' .. cmd, LOG_LEVEL)
dz.devices(FAKE_LMS).updateAlertSensor(dz.ALERTLEVEL_GREY, 'Off')
end
end
return
end
local function CheckWakeUpTime (P_wakeUpTimeHM)
-- function to check if the new wakeupTime is a time
dz.log('CheckWakeUpTime ' .. P_wakeUpTimeHM, LOG_LEVEL)
local F_wakeupTimeBool = false
local F_hhmmTime = string.gsub(P_wakeUpTimeHM, HHMM_SEPARATOR, "")
if tonumber(F_hhmmTime) ~= nil then -- it is a time
F_wakeupTimeBool = true
end
dz.log("CheckWupTime> hhmmTime " .. P_wakeUpTimeHM .. ' '.. tostring(F_wakeupTimeBool), LOG_LEVEL)
return(F_wakeupTimeBool)
end
local function ConvertWakeUpTime (P_wakeUpTimeHM)
-- function to convert wakeupTime in hh:mm:ss, if with separator like 'h'
dz.log('ConvertWakeUpTime ' .. P_wakeUpTimeHM, LOG_LEVEL)
local F_wakeUpTimeHMS
if HHMM_SEPARATOR ~= ":" then
F_wakeUpTimeHMS = (string.gsub(P_wakeUpTimeHM, HHMM_SEPARATOR, ":") .. ':00')
else
F_wakeUpTimeHMS = (P_wakeUpTimeHM .. ':00')
end
dz.log("ConvertWakeUpTime hhmmTime " .. F_wakeUpTimeHMS, LOG_LEVEL)
return(F_wakeUpTimeHMS)
end
local function SetNextAlarmTime()
local F_NextDayNum
local F_nextWakeTime
dz.log("SetNextAlarmTime nil", LOG_LEVEL)
-- set the time for the tomorrow alarm based on a list of the day of the week
F_NextDayNum = dz.time.wday + 1 -- Sunday = 1
if F_NextDayNum == 8 then F_NextDayNum = 1 end
F_nextWakeTime = alarmStartPerDay[F_NextDayNum]
dz.log("Day#: " .. F_NextDayNum .. ' ' .. F_nextWakeTime, LOG_LEVEL)
dz.log("Set next wakeup time: " .. F_nextWakeTime, LOG_LEVEL)
return (F_nextWakeTime)
end
local function CalculateNextAlarmInfos(P_wakeUpTimeState, P_Origin) -- P_Origin: 'U' User: after a change by GUI / 'S' Script for the next alarm day
local F_wakeUpTimeHM = P_wakeUpTimeState -- the time selected in the dummy selector
dz.log('CalculateNextAlarmInfos F_wakeUpTimeHM ' .. F_wakeUpTimeHM, LOG_LEVEL)
local F_wakeupTimeBool=CheckWakeUpTime(F_wakeUpTimeHM)
local F_wakeUpTimeHMS
if F_wakeupTimeBool then -- it is a time
dz.log('Wakeup time :' .. F_wakeUpTimeHM, LOG_LEVEL)
F_wakeUpTimeHMS=ConvertWakeUpTime(F_wakeUpTimeHM)
local F_checkAlarmTomorrow
if P_Origin == 'S' then -- if by the script, it is for tomorrow
F_checkAlarmTomorrow = true
else
F_checkAlarmTomorrow = dz.time.matchesRule('between ' .. F_wakeUpTimeHMS .. ' and 23:59:59')
-- if by the GUI, if the selected next alarm is before now, it is for tomorow
end
if F_checkAlarmTomorrow then
alarmDate=dz.time.addHours(24)
--print(tostring(checkExec))
dz.log('Set alarm for tomorrow ' .. F_wakeUpTimeHMS, LOG_LEVEL)
else
--print(tostring(checkExec))
alarmDate=dz.time
dz.log('Reset alarm for today ' .. F_wakeUpTimeHMS, LOG_LEVEL)
end
alarmTime= dz.time.makeTime(alarmDate.rawDate .. " " .. F_wakeUpTimeHMS) -- the wakeup time as a time object
alarmStatus='ON'
alarmIndex=1
else
if F_wakeUpTimeHM == alarmPauseValue then
dz.log('Alarm pause', LOG_LEVEL)
if alarmStatus == 'ON' then
-- alarm is ON and to be set on PAUSE, not a change of the trigger date/time
-- there should be already a next date/time set to be trigger the script again at the next alarm slot
dz.log('Alarm cancelled when ON', LOG_LEVEL)
else -- PLAY, OFF
alarmDate=dz.time.addHours(24) -- tomorrow to update the alarm for the day after
alarmTime=dz.time.makeTime(alarmDate.rawDate .. ' 12:00:00')
dz.log('Alarm cancelled when not ON', LOG_LEVEL)
end
alarmStatus='PAUSE'
elseif F_wakeUpTimeHM == alarmOffValue then
dz.log('Alarm stopped', LOG_LEVEL)
alarmDate=dz.time.addHours(-24) -- before today, not to be triggered
--print('alarmDate.rawTime ' .. alarmDate.rawTime)
--print('alarmDate.rawDate ' .. alarmDate.rawDate)
alarmTime=dz.time.makeTime(alarmDate.rawDate .. ' 12:00:00')
alarmStatus='OFF'
else
dz.log('CalculateNextAlarmInfos: Alarm ?????? <' .. F_wakeUpTimeHM .. '>', LOG_LEVEL)
end
--print('=> 3 alarmIndex ' .. alarmIndex)
alarmIndex=0
end
return
end
local function CancelAlarm() -- cancel the alarm after the icon is clicked
if alarmStatus=='PLAY' then
dz.log('CancelAlarm PLAY', LOG_LEVEL)
PlayLMS('Off')
elseif alarmStatus=='PAUSE' then
dz.log('CancelAlarm: alarm already on ' .. alarmStatus, LOG_LEVEL)
return(-1)
end
alarmStatus='CANCELLED' -- the next alarm will be set when the next timer happens
devWAKEUPTIME.setIcon(ICON_PAUSE)
dz.log('CancelAlarm => ' .. alarmStatus, LOG_LEVEL)
return(0)
end
local function GetAlarmInfo() -- get status, date and time of the alarm
alarmStatus=dz.variables(alarmStatus_idx).value
alarmDate=dz.variables(alarmDate_idx).date
alarmTime=dz.variables(alarmTime_idx).time
alarmIndex=dz.variables(alarmIndex_idx).value
--print('=> 4 alarmIndex ' .. alarmIndex)
if alarmStatus=='PAUSE' or alarmStatus=='ON' or alarmStatus=='PLAY' or alarmStatus== 'CANCELLED' or alarmStatus== 'OFF' then
dz.log('AlarmStatus OK: ' .. alarmStatus, LOG_LEVEL)
else
dz.log('AlarmStatus KO: ' .. dz.variables(alarmStatus_idx).value, LOG_LEVEL)
-------------SetNextAlarmTime(alarmOffValue)
alarmDate=dz.time.addHours(-24) -- tomorrow to update the alarm for the day after
alarmTime=dz.time.makeTime(alarmDate.rawDate .. ' 12:00:00')
alarmStatus='OFF'
alarmIndex=0
--print('=> 5 alarmIndex ' .. alarmIndex)
return(-1)
end
dz.log('Alarm status ' .. alarmStatus, LOG_LEVEL)
dz.log('Alarm date ' .. alarmDate.rawDate .. ' time ' .. alarmTime.rawTime, LOG_LEVEL)
return(0)
end
local function LangDayName(P_alarmDate) -- give the name of the day in user language (if dz GUI is not)
if userDayNames == nil then -- the day list exist
return(P_alarmDate.dayName)
else
return(userDayNames[P_alarmDate.wday])
end
end
local function SetIconNameDevice(P_alarmStatus, P_alarmDate)
if P_alarmStatus == 'PAUSE' then
devWAKEUPTIME.setIcon(ICON_PAUSE)
devWAKEUPTIME.rename(WAKEUPTIME_NAME .. ' - ' .. LangDayName(P_alarmDate))
elseif P_alarmStatus == 'OFF' then
devWAKEUPTIME.setIcon(ICON_OFF)
devWAKEUPTIME.rename(WAKEUPTIME_NAME)
elseif P_alarmStatus == 'PLAY' then
devWAKEUPTIME.setIcon(ICON_PLAY)
elseif P_alarmStatus == 'ON' then
devWAKEUPTIME.setIcon(ICON_ON)
devWAKEUPTIME.rename(WAKEUPTIME_NAME .. ' - ' .. LangDayName(P_alarmDate))
elseif P_alarmStatus == 'CANCELLED' then
-- the icon is already ok
else
dz.log('SetIconNameDevice ' .. P_alarmStatus .. ' unknown', dz.LOG_ERROR)
end
return
end
local function SetAlarmInfo(P_alarmStatus, P_alarmDate, P_alarmTime, P_alarmIndex) -- set status, date and time of the alarm
dz.variables(alarmStatus_idx).set(P_alarmStatus) --.checkFirst()
dz.variables(alarmDate_idx ).set(P_alarmDate.day..'/'..P_alarmDate.month..'/'..P_alarmDate.year) -- .checkFirst()
dz.variables(alarmTime_idx).set(P_alarmTime.hour..':'..P_alarmTime.min) -- .checkFirst()
dz.variables(alarmIndex_idx).set(P_alarmIndex)
--print('=> 6 alarmIndex ' .. P_alarmIndex)(
SetIconNameDevice(P_alarmStatus, P_alarmDate)
return
end
local function Blink(deviceId) -- 28/10/2020 -- move before PlayingKO to avoid error
-- blink a device based on time on and time off
dz.devices(deviceId).cancelQueuedCommands()
local blinkDurations= {2, 1, 2, 1, 2, 1}
local duration=0
local boolOn=true
for key, id in ipairs(blinkDurations) do
--print(duration)
if boolOn then
dz.devices(deviceId).switchOn().afterSec(duration)
boolOn=false
else
dz.devices(deviceId).switchOff().afterSec(duration)
boolOn=true
end
duration=duration+blinkDurations[key]
end
return
end
local function PlayingKO(playError)
-- in case of error when playing, do something to wakeup anayway...
dz.log('Error playing ' .. playError, dz.LOG_ERROR)
Blink(ERR_IDX) -- blink a specific device
return
end
local function CheckResponse() -- check http response -- 05/02/2021 -- move after PlayingKO to avoid error
if item.callback == CALLBACKPREFIX..'LMS_Status' then
-- check if the player is present (selected)
--dz.log('item.data ' .. item.data, LOG_LEVEL)
local CheckPlayer=string.find(item.data,'<option selected value="'..LMS_player)
if CheckPlayer ~= nil then -- the player is present
dz.log('HTTPResponse CheckPlayer OK ' .. CheckPlayer, LOG_LEVEL)
-- check if the player is playing
--dz.log('item.data ' .. item.data, LOG_LEVEL)
local CheckPlaying=string.find(item.data,'Now Playing')
if CheckPlaying ~= nil then -- the player is playing
dz.log('HTTPResponse CheckPlaying OK ' .. CheckPlaying, LOG_LEVEL)
else -- the player is not playing
dz.log('item.data ' .. item.data, dz.LOG_FORCE)
end
else -- the player is not present
PlayingKO('Player')
end
end
return
end
-----< END FUNCTIONS > ----------------------------------------------------------------------------------------
-- < Device trigger
if item.isDevice then -- the wakeup time has been changed
dz.log(dz.moduleLabel .. ' triggered by ' .. item.id .. ' ' .. item.name, LOG_LEVEL)
scriptRC=GetAlarmInfo()
if scriptRC ~= 0 then
SetAlarmInfo(alarmStatus, alarmDate, alarmTime, alarmIndex)
return
end
dz.log(devWAKEUPTIME.name .. ' ' .. devWAKEUPTIME.state .. " nValue: " .. devWAKEUPTIME.nValue, dz.LOG_DEBUG)
if devWAKEUPTIME.nValue == 0 and devWAKEUPTIME.state ~= alarmOffValue then -- the icon is clicked to cancel the alarm
scriptRC=CancelAlarm()
if scriptRC ~= 0 then
return
end
dz.log('==>> Alarm cancelled', LOG_LEVEL)
SetAlarmInfo(alarmStatus, alarmDate, alarmTime, alarmIndex)
else
-------SetNextAlarmTime(devWAKEUPTIME.state)
CalculateNextAlarmInfos(devWAKEUPTIME.state, 'U') -- user: after a change by GUI
SetAlarmInfo(alarmStatus, alarmDate, alarmTime, alarmIndex)
devWAKEUPTIME.switchSelector(devWAKEUPTIME.state).silent() -- to refresh icon and name selector on the GUI
end
-- < Timer to fire the alarm
elseif item.isTimer then
dz.log(dz.moduleLabel .. ' triggered by timer', LOG_LEVEL)
scriptRC=GetAlarmInfo()
if scriptRC ~= 0 then
SetAlarmInfo(alarmStatus, alarmDate, alarmTime, alarmIndex)
return
else
-- Wakeup management
local W_nextWakeTime
if alarmStatus == 'ON' or alarmStatus == 'PLAY' then
local wakeUpTimeHM = devWAKEUPTIME.state -- the time selected in the dummy selector
dz.log(alarmStatus .. ' Wakeup at ' .. wakeUpTimeHM .. ' slot ' .. alarmTime.rawTime .. ' ' .. alarmIndex, LOG_LEVEL)
if alarmDurations[alarmIndex]==0 then -- it was the last slot of the alarm
PlayLMS('Off')
W_nextWakeTime = SetNextAlarmTime() -- set alarm for next day
CalculateNextAlarmInfos(W_nextWakeTime, 'S') -- script
dz.log('Off alarmIndex ' .. alarmIndex, LOG_LEVEL)
else -- it is a slot to play
alarmStatus='PLAY'
PlayLMS('On', alarmLevels[alarmIndex], alarmPlayLists[alarmIndex],alarmShuffle[alarmIndex])
alarmTime=alarmTime.addMinutes(alarmDurations[alarmIndex])
--print('=> 1 alarmIndex ' .. alarmIndex)
alarmIndex=alarmIndex+1
dz.log('=> On alarmIndex ' .. alarmIndex, LOG_LEVEL)
W_nextWakeTime = devWAKEUPTIME.state
end
elseif alarmStatus =='CANCELLED' or alarmStatus =='PAUSE' then -- set alarm for next day
W_nextWakeTime = SetNextAlarmTime() -- set alarm for next day
CalculateNextAlarmInfos(W_nextWakeTime, 'S') -- script
else
dz.log('Alarm status: ' .. alarmStatus .. ' ?!?', dz.LOG_ERROR)
return
end
SetAlarmInfo(alarmStatus, alarmDate, alarmTime, alarmIndex)
devWAKEUPTIME.switchSelector(W_nextWakeTime).silent() -- and to refresh icon and name selector on the GUI
end
-- < The callbacks to check if the player is playing
elseif item.isHTTPResponse then -- the callback to check error code and player status
dz.log(dz.moduleLabel .. ' callbacked by ' .. item.callback, LOG_LEVEL)
if item.ok then -- statusCode == 2xx
dz.log('HTTPResponse OK !!! callback: ' .. item.callback .. ' statusCode: ' .. item.statusCode, LOG_LEVEL)
CheckResponse()
else -- error http
dz.log('HTTPResponse KO !!! callback: ' .. item.callback .. ' statusCode: ' .. item.statusCode, dz.LOG_ERROR)
--if item.callback == CALLBACKPREFIX..'LMS_Play' then --Error playing alarm
dz.log('Backup alarm to fire!!!', LOG_LEVEL)
PlayingKO('HTTPResponse')
--else
-- dz.log('HTTPResponse KO for something else?!?', dz.LOG_ERROR)
--end
end
-- < Impossible error!
else
dz.log(dz.moduleLabel .. ' triggered by ?????', dz.LOG_ERROR)
end
end
} updated on 08/02/2021 fix the logging and an error due to new dz version
The configuration is done with variables explained in the script
I comment the following ones:
- The normal wake-up time for each day of the week, Pause for the days you don’t want an alarm
alarmStartPerDay = {'Pause', '6h40', '6h40', '6h40', '6h40', '6h40', '7h15'} the first one is Sunday, but perhaps depends on settings.
They have to be present in the selector WAKEUPTIME_IDX so one could change it.
- alarmDurations = {5, 30, 40, 0} -- alarm duration for each slot - 0 to stop the last alarm
- alarmPlayLists = {"zzReveilMusic","zzReveilInfo", "zzReveilDeezer"} -- playlists names for each slot /!\ no blank nor é à ...
- alarmLevels = {60, 77, 60} -- alarm level for each playlist
- alarmShuffle = {true, false, true} -- to shuffe or not each alarm slot
There is also a fallback possibility is case the LMS doesn’t play ; I blink a light (ERR_IDX)
If Domoticz missed the wakeup time (for some cause), when Domoticz could do something after, it will play the LMS.
As all the wanted methods for the LMS doesn’t exist in DzVents, I used direct api and so I need 2 sort of id for the LMS
local LMS_player= "b8:27:eb:7d:00:36" -- LMS Player MAC Address for json commands
local LMS_serverPort='erato:9000' -- LMS Server Hostname and HTTP Port Number
It is a morning wakeup alarm ; I’m not sure it works to wake up after noon
Next steps
Better widget?
More configuration via GUI rather than in the script…
Build a device like Oregon Projection Clocks to display if there an alarm on and other info from Domoticz like temperature… But I didn’t find anything regarding the projector…
Disclaimer: I'm not responsible if you don't wake up on time to "go" to work