Hej,
har funderat på motorvärmaren lite.
Det är inga problem att implementera det i ER - frågan är bara att göra det hyfsat elegant... Det är dessutom alltid lite krångligt med timers och alla specialfall som ofta inträder. Nåväl, här är ett försök...
Jag har inkluderat en ny version av VDn.
Alla knappar har samma kod
Code: Select all
local VDID = fibaro:getSelfId()
local scene = fibaro:getValue(VDID, "TCPPort")
local event = {type='MV_VD', id=VDID, value=_elementID_}
fibaro:startScene(scene,{urlencode(json.encode(event))})
Så, vad knappen gör (och alla knappar i VDn) är att den skickar ett event till sceneID som finns i VDns TCP port fält.
Eventet är av typ:
Code: Select all
#MV_VD{id=<VD id>, value=<knapp id>}
och vi kan därför skriva ER regler som
Code: Select all
rule("#{id=46, value=4} => log('VD 46 klickade på knapp med id 4')")
Ok, ER har en funktion som heter VDev.proxy(<VD id>) som returnerar ett objekt med metoder för att lättare jobba med en VD.
Ex.
Code: Select all
local vd = VDev.proxy(46)
vd.setValue('Travel','07:00') -- Sätter fältet ui.Travel.label i VD 46 till '07:00'
local name = vd.nameOf(2) -- returnerar 'Travel' om ui.Travel.label är fält 2 i VDn.
Så, om vi har det, kan vi skriva vår motorvärmarscen så här:
Code: Select all
local BTNS = {"Travel","Hplus","Hminus","Mplus","Mminus","Temp","Status","Auto","On","Off","Heating"} -- Name of fields in VD
VD1,VD2=144,133 -- VD IDs
Users = {[VD1]={heater=17},[VD2]={heater=19}} -- deviceID for heaters
User1,User2=Users[VD1],Users[VD2] -- Remove VD2 if only one VD
outsideTemp = 299 -- ID of temp device
runTime = 0
--Initialize VD at restart
for vd,u in pairs(Users) do
u.vd=VDev.proxy(vd) -- Create proxy to easier interact with VD
local a = u.vd.getValue("Travel") -- See if we have an old travel value and reuse it
u.vd.setValue("Travel",a and a~="" and a or "07:00") -- else default to 07:00
u.travel = toTime(u.vd.getValue("Travel"))
u.status = fibaro:getValue(u.heater,"value") == '0' and 'Av' or 'På' -- Status of heater currently
Event.post({type='Update',user=u}) -- Update fields in VD
end
-- Convert events from ID to easier events to handle...
rule("#MV_VD{id='$id',value='$value'} => post({type=Users[id].vd.nameOf(value), user=Users[id],_sh=true})")
-- Buttons pressed in VD
rule("#Hplus{user='$user'} => user.travel=(user.travel+01:00) % 24:00; post(#Update{user=user})")
rule("#Hminus{user='$user'} => user.travel=(user.travel-01:00) % 24:00; post(#Update{user=user})")
rule("#Mplus{user='$user'} => user.travel=(user.travel+00:01) % 24:00; post(#Update{user=user})")
rule("#Mminus{user='$user'} => user.travel=(user.travel-00:01) % 24:00; post(#Update{user=user})")
rule("#On{user='$user'} => user.heater:on") -- Turn on heater
rule("#Off{user='$user'} => user.heater:off") -- Turn off heater
rule("#Auto{user='$user'} & user.status == 'Av' => user.status = 'Auto'; post(#Update{user=user})")
-- Generic handler to update VD when a value changes (and set timer if needed)
rule([[#Update{user='$user'} =>
user.vd.setValue('Status',user.status); -- Update status
user.vd.setValue('Travel',osdate('%H:%M',user.travel+midnight)); -- Update travel time
user.vd.setValue('Temp',outsideTemp:value); -- Update temp
user.vd.setValue('Heating',osdate('%H:%M',midnight+user.travel-runTime)); -- Update heater time
cancel(user.timer); -- Cancel ev. timer
user.timer=nil;
local startTime = user.travel+midnight;
if startTime < ostime() then startTime += 24:00 end; -- Avresa passed, bump to next day
startTime -= runTime;
if startTime < ostime() then startTime=ostime() end; -- Time passed, set to now
if user.status == 'Auto' then -- If auto mode, start timer
log('Startar motorvärmare %s',osdate('%c',startTime));
user.timer = post(#On{user=user},startTime)
end;
user.vd.setValue('Heating',osdate('%A %H:%M',startTime)); -- Update heater time (day in HC2 language)
]])
rule("User1.heater:isOn => cancel(User1.timer); User1.status='På'; post(#Update{user=User1})")
rule("User1.heater:isOff => cancel(User1.timer); User1.status='Av'; post(#Update{user=User1})")
rule("User2.heater:isOn => cancel(User2.timer); User2.status='På'; post(#Update{user=User2})") -- remove if only one user
rule("User2.heater:isOff => cancel(User2.timer); User2.status='Av'; post(#Update{user=User2})") -- remove if only one user
rule([[outsideTemp:value => -- Outside temp changes, update user values
local outTemp = outsideTemp:value;
runTime = math.floor(60+100*outTemp/(outTemp-35));
if outTemp>10 then runTime=0 end;
runTime *= 60;
post(#Update{user=User1});
post(#Update{user=User2}) -- remove if only one user
]]).start()
Den hanterar 2 VD just nu, kan enkelt modifieras till en eller godtyckligt många.
värmare och temperatur deviceIDs måste deklareras under %% properties så att reglerna triggas när de ändras.
Logiken är att när Auto är satt så kör timern. På/Av slår på/av värmaren. Om man sätter auto när tiden har passerat så sätts timern till nästa dag. Om uppvärmningstiden är för liten så startas värmaren direkt. Om man slår på/av värmaren manuellt så uppdateras VDn.
Scenen behöver inte heller kontinuerligt polla VDn för värden då den bara reagerar på knapptryck och när temperaturen ändras.
Man kan modifiera den så att man har dagar också antar jag. Tyvärr har jag varken bil eller motorvärmare
Men principen, att ha en VD där alla knappar bara skickar ett event till ER scenen och all logik hanteras i ER, är ngt som jag använder i mina andra VDs.