Jump to content

Welcome to Smart Home Forum by FIBARO

Dear Guest,

 

as you can notice parts of Smart Home Forum by FIBARO is not available for you. You have to register in order to view all content and post in our community. Don't worry! Registration is a simple free process that requires minimal information for you to sign up. Become a part of of Smart Home Forum by FIBARO by creating an account.

 

As a member you can:

  •     Start new topics and reply to others
  •     Follow topics and users to get email updates
  •     Get your own profile page and make new friends
  •     Send personal messages
  •     ... and learn a lot about our system!

 

Regards,

Smart Home Forum by FIBARO Team


Search the Community

Showing results for tags 'scenesmove'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • FIBARO Community
    • FIBARO Portal and Forum policy
    • FIBARO
    • Say hello!
    • Off-topics
  • FIBARO Update
    • FIBARO System Update
    • FIBARO Mobile Update
  • FIBARO Community Support
    • Scenes and Interface
    • FIBARO Products
    • FIBARO Mobile
    • FIBARO HomeKit
    • FIBARO Assistant Integrations
    • Other Devices / Third-party devices
    • Tutorials and Guides
    • Home Automation
    • Suggestions
  • FIBARO Społeczność
    • FIBARO
    • Przywitaj się!
    • Off-topic
  • FIBARO Aktualizacja
    • FIBARO System Aktualizacja
    • FIBARO Mobile Aktualizacja
  • FIBARO Wsparcie Społeczności
    • Sceny i Interfejs
    • FIBARO Urządzenia
    • FIBARO Mobilnie
    • FIBARO HomeKit
    • Integracja z Amazon Alexa i Google Home
    • Urządzenia Firm Trzecich
    • Poradniki
    • Automatyka Domowa
    • Sugestie

Categories

  • Scenes
  • Virtual Devices
  • Quick Apps
  • Icons

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Facebook


Google+


Skype


Website URL


WhatsApp


Country


Gateway/s


Interests

  1. I messed up some code tags so re-posting... Hi Here is my small tutorial on the alarm system code i use to complement the rfid keypad system. Firstly you need to create an 'ALARM' variable with at least 2 values. one variable will be OFF second variable will be FULL (or whatever name you want to give) you could if you wanted create many more variables for different zone eg i have a 3rd called DOWN you then programme the keypads (or any other scene) to change the variable to the alarm mode you want --[[ %% properties 145 value 146 value 159 value 160 value %% events %% globals --]] local alarm = fibaro:getGlobal("alarm") local kpof = fibaro:getValue(145, 'value') local kpon = fibaro:getValue(146, "value") local bkon = fibaro:getValue(159, "value") local bkof = fibaro:getValue(160, "value") if ( ((kpon == '1') or ( bkon == '1')) and (alarm == 'off') ) then fibaro:setGlobal("alarm", "down") end if ( ((kpon == '1') or (bkon == '1')) and (alarm == 'down') ) then fibaro:setGlobal("alarm", "full") end if ( (bkof == '1') or (kpof == '1') ) then fibaro:setGlobal("alarm", "off") end From above i have 2 keypads. I have put triggers under the properties for both ON and OFF when i press the 'ON' button once it changes the VARIABLE to PART, if i then press again it changes the VARIABLE to FULL. If you wanted you could continue this for more zones but it can get a bit complicated...... Finally if either of the OFF buttons are pressed the VARIABLE is set to OFF. Next part is the actual setting of the alarm.. --[[ %% properties %% events %% globals alarm --]] if (fibaro:countScenes() > 1) then fibaro:debug('NO!') fibaro:abort() end fibaro:sleep(12*1000) -- set delay time here mine is 12 seconds local alarm = fibaro:getGlobal("alarm") local downArmIds = {} -- set ID's for DOWN mode local fullArmIds = {} -- set ID's for FULL mode local deviceIds = {} -- leave blank as it will auto fill -- single 'alarm' variable with multiple arguments -- in one place (lists above) if (alarm == 'full') then deviceIds = fullArmIds elseif (alarm == 'down') then deviceIds = downArmIds elseif (alarm == 'off') then fibaro:abort() end local unsafeDevices = {} -- will add unsafe devices to this empty list local statusMessage = "" -- will get changed to push message depending on outcome below -- below loops through all devices to check device values are safe, i.e. '0' -- otherwise adds the devices to unsafe list in preparation for push message local armStatus = 'safe' for i, id in ipairs(deviceIds) do if (fibaro:getValue(id, "value") == '0') then deviceStatus = 'safe' else deviceStatus = 'unsafe' table.insert(unsafeDevices, id) armStatus = 'unsafe' end print("Id: " .. id .. " " .. fibaro:getName(id) .. " is " .. deviceStatus) end print("\nArm status is " .. armStatus) -- if unsafe, then formulates the push message, otherwise sets the device to arm if (armStatus == 'unsafe') then -- loops each device in unsafeDevices list to specify the all the names of device to be -- included in push message for i, id in ipairs(unsafeDevices) do statusMessage = statusMessage .. fibaro:getName(id) .. " ; " end statusMessage = statusMessage .. " unsafe to arm.\nAlarm not set" fibaro:setGlobal("alarm", "off") --[[ Example message... "Front Door; Living Room Motion; Studio Door Lock; unsafe to arm. Alarm not set" ]]-- else -- loops devices to set them to arm status for i, id in ipairs(deviceIds) do fibaro:call(id, "setArmed", "1") end statusMessage = "Alarm set to " .. fibaro:getGlobal("alarm") --[[ Example message... "Alarm set to full" or "Alarm set to part" ]]-- end fibaro:call(319, 'sendPush', statusMessage) -- push message to me change 319 accordingley -- add any other code here that you want to run eg turn lights off or heating off etc print(statusMessage) -- prints in debug window this looks big but you only need to add the device ID's of your FULL mode, DOWN mode and any other message once the alarm has been set. Remember to separate your ID numbers with a comma The code is triggered by a change in the global variable called 'alarm'. This then starts the scene. The time delay gives you time to press again for different modes and also to leave the house and make sure that all sensors become safe. (i have set my motion sensors to show as being safe after 5 secs, the default is around 15 secs). After the time delay it checks which variable is set, then it only checks those sensors to make sure they are all SAFE. If they are SAFE then it proceeds to ARM those sensors and then sends you a push message that the alarm has been set and will run any additional code you have added eg turn off the lights, heating etc If they are UNSAFE then it aborts the arming procedure and sends you a message that 'a named sensor is unsafe to arm', you can then investigate and make sure it is safe before starting again. examples include if a door was left ajar or window is left open etc Next part is the ACTIVATION code: --[[ %% properties 25 value 85 value 95 value 148 value 90 value 171 value 176 value 166 value 32 value 45 value %% events %% globals --]] function activation() local trigger = fibaro:getSourceTrigger() --fibaro:debug(trigger) local device = fibaro:getName(trigger['deviceID']) fibaro:debug(device) local subject = 'alarm activated' local message = 'alarm activated ' fibaro:call(2,'sendEmail',subject,message..device) -- ID of user '2' is always admin fibaro:call(319,'sendPush',message..device) -- ID of my phone end local alarm = fibaro:getGlobal("alarm") local downArmIds = {} local fullArmIds = {} local deviceIds = {} if (alarm == 'full') then deviceIds = fullArmIds elseif (alarm == 'down') then deviceIds = downArmIds elseif (alarm == 'off') then fibaro:abort() end for i, id in ipairs(deviceIds) do if ( (fibaro:getValue(id, "value") == '1') and (fibaro:getValue(id, "armed") == '1') and (alarm ~= 'off') ) then activation() -- this is function above fibaro:call(123, "turnOn") -- code for turning siren on fibaro:sleep(10*60*1000) -- 10 min delay change to what you want fibaro:call(123, "turnOff") -- code for turning siren off -- plus any other code you want to add end end firstly you need to enter the ID numbers of all your sensors in the properties section as triggers except the entry zonesalso the fullArmIds and downArmIds need to match the previous arming code except for the entry doors we have a separate entry code to give us a time delayed entry1st block is the function activation(), this basically tells me via push message and email which sensor triggered my alarm2nd block checks to see which mode the alarm is in and therefore will only monitor those specific ID's3rd block will cause the alarm to trigger if our 'armed' devices are breached and run the activation code Entry code is below this as name suggests gives us a defined time to enter property and switch off alarm before it activates: --[[ %% properties 82 value 83 value %% events %% globals --]] local fda = fibaro:getValue(82,'armed') -- front door armed local fdv = fibaro:getValue(82,'value') -- front door value local bda = fibaro:getValue(83,'armed') -- back door armed local bdv = fibaro:getValue(83,'value') -- back door value local alarm = fibaro:getGlobalValue("alarm") function activation() local trigger = fibaro:getSourceTrigger() --fibaro:debug(trigger) local device = fibaro:getName(trigger['deviceID']) fibaro:debug(device) local subject = 'alarm activated' local message = 'alarm activated ' fibaro:call(2,'sendEmail',subject,message.. device) fibaro:call(319,'sendPush',message.. device) end if ( ( (fda == '1') and (fdv == '1') and (alarm~='off') ) or ( (bdv == '1') and (bda == '1') and (alarm~='off') ) ) then fibaro:sleep(30*1000) -- 30 sec delay local alarm = fibaro:getGlobalValue("alarm") if (alarm == 'off') then fibaro:abort() else activation() fibaro:call(123, "turnOn") fibaro:sleep(10*60*1000) fibaro:call(123, "turnOff") end end to start with set the ID of your entry zones under properties, and update the ID 82 and 83 with your own. If you have just 1 then delete accordingley and more than 2 then just add the extra as needed the function is same as before the final block checks if the doors have been opened if they are armed and the alarm is NOT set to off it then starts a 30 sec timer. Just amend 30 to whatever time you need. once the timer has counted down it will check the variable again and if you have turned alarm off then code aborted. if alarm not switched off then activation procedure starts just as before and sends push message, email and siren activates for 10 mins. Final part is turning the alarm off --[[ %% properties %% events %% globals alarm --]] local alarm = fibaro:getGlobal("alarm") local deviceIds = {} if ( alarm == 'off' ) then fibaro:call(319, "sendPush", "Alarm Off") -- my phone fibaro:call(123, "turnOff") -- siren -- any other code for i, id in ipairs(deviceIds) do fibaro:call(id, "setArmed", "0") end end fill the deviceIds with the values of ALL YOUR SENSORS - incl entry sensors the trigger for this is the global variable alarm if its in the 'off' setting then it will send me a push message and send an 'off' command to siren (just in case it was activated) it will then go through the sensors 1 by 1 and disarm them all I hope this helps all of you and any questions and feedback and comments please feel free to leave them thanks
  2. Hi, it is possible to use the jpg-stream of the netatmo welcome in your own lan and without the netatmo api. I've written a scene to detect the correct url for the camera settings of the HC2 over the netatmo api. (See screens) Somebody interested? It is a first beta version because the url could change from times to times. At the moment I don't know and we have to test it. --[[ %% properties %% globals --]] -- DIESE DATEN ANPASSEN local client_id = '563a791369f740XXXXXXX' local client_secret = 'OmHqQ551M6Ww8vbTgGMWXXXXXX' local username = '[email protected]' local password = 'XXXXXXXX' local language = 'english' -- german/english -- AB HIER NICHTS MEHR ANPASSEN local token = '' local request_body = '' Debug = function ( color, message ) if (debug == 1) then fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span")) elseif (debug == 0) then end end DebugChange = function ( color, message ) fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span")) end DebugError = function ( color, message ) fibaro:debug(string.format('<%s style="color:%s;">%s', "span", color, message, "span")) end fibaro:debug('netatmo welcome cam finder v1.0b') if (language == 'german' or language == 'english') then DebugError( "green", "Debug: " ..language) else DebugError( "red", "Please choose a language for debug") fibaro:abort(); end local sourceTrigger = fibaro:getSourceTrigger(); function oAuth(nextFunction) local request_body = 'grant_type=password&client_id=' .. client_id .. '&client_secret=' .. client_secret .. '&username=' .. username .. '&password=' .. password .. '&scope=read_camera access_camera' getResponseData('https://api.netatmo.net/oauth2/token', request_body, function(data) if (data.access_token ~= nil) then token = data.access_token gethomedata() else if (language == 'german') then DebugError( "red", "oAuth-API-Call konnte nicht durchgeführt werden! oAuth 2.0 lieferte keinen Wert zurück") elseif (language == 'english') then DebugError( "red", "oAuth-API-Call Error. oAuth 2.0 returns nothing.") end end end ) end function getResponseData(url, body, func) local http = net.HTTPClient() http:request(url, { options = { method = 'POST', headers = { ['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8' }, data = body }, success = function(response) func(json.decode(response.data)) end }) end function gethomedata() request_body_cam = 'access_token=' ..token.. '' getResponseData('https://api.netatmo.net/api/gethomedata', request_body_cam, function(getData) --fibaro:debug(request_body_cam) if (getData.body ~= nil) then if (language == 'german') then DebugError( "green", "API-Call durchgeführt.") elseif (language == 'english') then DebugError( "green", "API-Call was done.") end for w, v in pairs(getData.body.homes) do for a, b in pairs(v.cameras) do if (b.is_local) then if (language == 'german') then DebugError( "green", "Lokale IP der Kamera gefunden.") elseif (language == 'english') then DebugError( "green", "Local IP of cam was found.") end findLocalWelcome(b.vpn_url) else if (language == 'german') then DebugError( "green", "Lokale IP der Kamera NICHT gefunden.") elseif (language == 'english') then DebugError( "green", "Local cam NOT found.") end end end end else if (language == 'german') then DebugError( "red", "API-Call fehlgeschlagen") elseif (language == 'english') then DebugError( "red", "API-Call Error") end end end ) end function findLocalWelcome(url) local selfhttp = net.HTTPClient({timeout=2000}) url = url..'/command/ping' selfhttp:request(url, { options={ headers = selfhttp.controlHeaders, method = 'GET', timeout = 5000 }, success = function(status) if status.status == 200 then if status.data ~= nil then --print(json.decode(status.data)) for k,v in pairs(json.decode(status.data)) do if (k == 'local_url') then local cam_url = v local url_new = string.sub(cam_url, 8, #cam_url) one, two = url_new:match("([^,]+)/([^,]+)") fibaro:debug('Cam-IP: '..one) fibaro:debug('JPG-Stream: /'..two.. '/live/snapshot_720.jpg') DebugError( "green", "coded 4 siio.de/siio.com") end end end else print ("failed") print(status.data) end end, error = function(error) print "ERROR" print(error) end }) end oAuth() Greetings
  3. Main scene FTBE v 1.3.4 Hello everyone! NEW version is OUT! More about scene and download you can find here: WHAT'S NEW: Main scene FTBE 1.3.4 - changed function for time of day calculation and added use of SleepState global to set time of day to morning when Awake regardless of current time Main scene FTBE 1.3.0 - cleaned some bugs, added some more checks to prevent scene from stop running due to errors. Optimized and compacted code, removed unnecessary comments. DemoMode only stops changing timers while user code and scheduled events will continue to execute. Darkness can now be changed by measured lux level or global variable that is set to lux value measured by light measuring devices placed outside. Scene is now running on setTimeout function instead on sleep for better timing and also aligns to 0 seconds or exact minute. Sunrise & Sunset VD v1.4.0 - Modified main loop code to better handle global variables. Variables are now automatically repaired and are not reset to default settings after HC2 reboot. Added variable SunriseIcon to store VD icon ID and now when main icon for VD is set also all button icons are set automatically. Home Status VD v1.1 - Added variable HomeStatIcon to store VD icon ID and now when main icon for VD is set also all button icons are set automatically. Added label that shows most important values on VD when closed. Home Timers VD v1.1 - Added variable HomeTimersIcon to store VD icon ID and now when main icon for VD is set also all button icons are set automatically. Added label that shows most important values on VD when closed. NOTE - This version is compatible with previous versions so need to do any changes in your current code of other scenes and VD's. REQUEST - If you like my work and found it useful please give me support by rating and writing short review. Thank you! PS Dear friends from Slovakia you can find this scene and VD translated to your language here: HomeSystem.sk
  4. Bank Holiday Calc Scene (V 1.2.3a) I started creating a scene where the bank Holidays can be calculated, at the moment Switzerland (alle Kantone), Germany (alle Bundesländer), Austria (alle Bundesländer), United Kingdome (all Countries), France (some Départements), Sweden (whole Country), Ireland (whole Country), Iceland (whole Country), Poland (whole Country), Italy (whole Country), Norway (whole Country), Croatia (whole Country), Netherlands (whole Country), Czech Republic (whole Country, thanks @petr23) are covered. Work in progress for more Countries to come. With this scene you can calculate all the Bank Holidays of the current year. There are some preset Countries with already defined Holidays, some also have Provinces as there may be different holidays in parts of the country. The yearly bank Holidays will be stored in the global Variable "BankHol_ThisYear" (in System Seconds). You can either use this list as you wish or implement it into Sankotronic's Main Scene for Time Based Events Control (setup described below). The Names/Titles of the Bank Holidays are provided in multiple Languages and it is set up that more language or your own language can be supported. Setup You need to create a global variable with the Name "BankHol_ThisYear" in the upper part of the variable Panel. If you wish to check constantly if today or tomorrow is a Bank Holiday, then you need to implement a function in @Sankotronic's Main Scene for Time Based Events Control. ************************ SETUP ************************** Create global Variable "BankHol_ThisYear" in the upper part of the variable Panel. If you want to implement the funcsion in Sankotronic's MAIN SCENE FOR TIME BASED EVENTS CONTROL you can check with a function called doBankHolidays() if the current day or the next day are Bank holidays. For this you also need two more variables: - BankHoliday - BankHolidayTomorrow both should be initialized with a 0. The function will set the variables to 1 if there is a Bank Holiday today or tomorrow. If the Function is not yet implemented in the base Version by Sankotronic, then add the following code above the MAIN LOOP PART. ************************** New FUNCTION For MSFTBEVC by Sankotronic ************************** function doBankHoliday() if fibaro:getGlobalValue("BankHol_ThisYear") ~= nil then --only perform if there is a global Variable BankHol_ThisYear local local_bankHolidays = json.decode(fibaro:getGlobalValue("BankHol_ThisYear")) --get the global Value from Variable fibaro:setGlobal("BankHoliday", 0) -- set Variable to 0 before checking today = os.time({year = os.date('*t',os.time()).year, month = currentmonth, day = currentday}) for k,v in pairs(local_bankHolidays) do if(today == v) then fibaro:setGlobal("BankHoliday", 1) --set Variable to 1 if exDebug then logbug("lightblue", "Today is a Bankholiday ("..k..")") end; break end end fibaro:setGlobal("BankHolidayTomorro", 0) -- set Variable to 0 before checking tomorrow = os.time({year = os.date('*t',os.time()).year, month = currentmonth, day = currentday}) + (24*3600) for k,v in pairs(local_bankHolidays) do if(tomorrow == v) then fibaro:setGlobal("BankHolidayTomorro", 1) --set Variable to 1 if exDebug then logbug("lightblue", "Tomorrow is a Bankholiday ("..k..")") end; break end end end end ************************** New FUNCTION For MSFTBEVC by Sankotronic **END ************************ In the MAIN LOOP PART you also need to call the function doBankHoliday(). Do this by adding doBankHoliday() above the following Lines: -- change value of global variable doGlobalSched(); ************************** Scheduling of the Scene ************************** I run this Scene daily at 00:15 (to move Load away from 00:00), you can also only call it once at the beginning of the new year. Here is the Setup in MSFTBEVC in the part of SCHEDULED SCENES SETUP: local runSceneSchedName = {"Calculate BankHoliday List"} local runSceneSchedID = {jT.scene.BankHolidayCalc}; (or the ID of your Scene if you are not using HomeTable local runSceneSchedHour = {{"00:15"}}; local runSceneSchedWeek = {{1,1,1,1,1,1,1}}; local runSceneSchedPushFlag = {{0}}; local runSceneSchedPushMessage = {{0}}; ************************ Scheduling of the Scene END ************************** ************************ SETUP END ************************** User Variables Country choose your country by changing the Code between the brackets (capital Letters) local country = "CH" Available Countries: CH = Switzerland DE = Germany AT = Austria GB = United Kingdom FR = France SE = Sweden IE = Ireland IS = Iceland PL = Poland IT = Italy NO = Norway HR = Croatia CZ = Czech Republic NL = Netherlands Province choose your province by changing the Code between the brackets (small Letters). If you do not wish to use a province you can keep the quotes empty "". local province = "zh" Available Provinces Switzerland: ag = Argau, ar = Appenzell Ausserrhoden, ai = Appenzell Innerrhoden, bl = Basel-Landschaft, bs = Basel-Stadt, be = Bern, fr = Freiburg, ge = Genf, gl = Glarus, gr = Graubünden, ju = Jura, lu = Luzern, ne = Neuenburg, nw = Nidwalden, ow = Obwalden, sh = Schaffhausen, sz = Schwyz, so = Solothurn, sg = St. Gallen, ti = Tessin, tg = Thurgau, ur = Uri, vd = Waadt, vs = Wallis, zg = Zug, zh = Zürich Germany: bw = Baden-Württemberg, by = Bayern, be = Berlin, bb = Brandenburg, hb = Bremen, hh = Hamburg, he = Hessen, mv = Mecklenburg-Vorpommern, ni = Niedersachsen, nw = Nordrhein-Westfalen, rp = Rheinland-Pfalz, sl = Saarland, sn = Sachsen, st = Sachsen-Anhalt, sh = Schleswig-Holstein, th = Thüringen Austria: b = Burgenland, k = Kärnten, n = Niederösterreich, o = Oberösterreich, s = Salzburg, st = Steiermark, t = Tirol, v = Vorarlberg, w = Wien United Kingdom: eng = England, sct = Scotland, wls = Wales, nir = Nord Ireland France: moselle = Moselle, basrhin = Bas-Rhin, hautrhin = Haut-Rhin Sweden: No Provinces (all public holidays apply for whole Country) Ireland: No Provinces (all public holidays apply for whole Country) Iceland: No Provinces (all public holidays apply for whole Country) Poland: No Provinces (all public holidays apply for whole Country) Italy: No Provinces (all public holidays apply for whole Country) Norway: No Provinces (all public holidays apply for whole Country) Croatia: No Provinces (all public holidays apply for whole Country) Czech Republic: No Provinces (all public holidays apply for whole Country) Netherlands: No Provinces (all public holidays apply for whole Country) Language choose your language by changing the Code between the brackets (small Letters) local titleLanguage = "de" en = English de = German fr = French sv = Swedish ga = Gaelic / Irish is = Islandic pl = Polish no = Norwegian it = Italian hr = Croatian cz = Czech nl = Dutch ol = own language The Texts are always given in the available languages. If there is no Title for your chosen language, default language English will be taken. There is also a key for your Own Language (ol) Add the text in your language in the lines with the ["ol"] keys, just change the whole text in "OL xxx" after the equal-sign. If you want to change the Title in an existing language for example German "de", then change it at the specific line where the key ["de"] is set. Example: in xmasDayTitle you want to rename the German translation then change the Text in the line xmasDayTitle["de"] = change it from "Weihnachten" to "1. Weihnachtsfeiertag" In this section I also tried to explain the Holiday as good as possible. This might need some improvement in future Versions. --Easter Sunday / Oster Sonntag easterSundayTitle = {} easterSundayTitle["en"] = "Easter Sunday" easterSundayTitle["de"] = "Oster Sonntag" easterSundayTitle["fr"] = "Pâques" easterSundayTitle["ol"] = "OL Easter Sunday" --January First / Neujahrstag januaryFirstTitle = {} januaryFirstTitle["en"] = "January First" januaryFirstTitle["de"] = "Neujahrstag" januaryFirstTitle["fr"] ="Nouvel An" januaryFirstTitle["sv"] ="nyårsdagen" januaryFirstTitle["ol"] = "OL January First" --2. January / Berchtoldstag (Switzerland) / 2. January januarySecondTitle ={} januarySecondTitle["en"] = "2nd New Years Day" januarySecondTitle["de"] = "Berchtoldstag" januarySecondTitle["fr"] = "Saint Berchtold" januarySecondTitle["ol"] = "OL 2nd New Years Day" --Christmas Day / Weihnachten / 25. Dec xmasDayTitle = {} xmasDayTitle["en"] = "Christmas Day" xmasDayTitle["de"] = "Weihnachten" xmasDayTitle["fr"] = "Nöel" xmasDayTitle["sv"] = "juldagen" xmasDayTitle["ol"] = "OL Christmas Day" ... ... ... Show Sundays There are some holidays that always fall on a Sunday (like Easter Sunday or Pentecost) these are not shown by default. If you want to add them, then you will have to set the variable "addSundays" to true. If set to false, these days are not shown/detected. This setting does not exclude a holiday if it is a fixed day and hits a Sunday (like Swiss National day at 1. August), these days will always show. local addSundays = false Debuggig There are some switches to enable Debugging: local debug = true local debugSpecificYear = false local debugYear = 2015 If debug is set to true, then it will print the Results in an ordered List (Name = Date) in the Scene. If you wish to check for a specific year to see if the calculations are correct, then set debugSpecificYear to true and choose the year in debugYear. Above it would check for the holidays in 2015 if debugSpecificYear were set to true. Result A JSON in the below format will be stored in the global Variable BankHol_ThisYear: {"Pfingstmontag":1654509600,"Neujahrstag":1641034800,"Reformationstag":1667214000, "Auffahrt":1653559200,"Stephanstag":1672052400,"1. Mai":1651399200, "Buss- und Bettag":1668596400,"Tag der Deutschen Einheit":1664791200, "Weihnachten":1671966000,"Oster Montag":1650276000,"Karfreitag":1650016800} Corrections Even though I have tested the dates thoroughly there might be mistakes in the calculations. Before using the Scene in a vital Environment (Alarms, etc.) please check the list first in Debug Mode. Please also let me know if I made a mistake, then I can correct it for future users. Improvements I will be adding more countries over the time. For certain Countries I am sure I'd need help from locals as these days are sometimes not easy to define. Version History 1.2.3a Fixed some Netherlands Holiday Names 1.2.3 Added Czech Republic, Netherlands 1.2.2 Added Norway, Italy, Croatia 1.2.1 Added Iceland, Poland 1.2.0 Introduced new Variable to add Sundays to the days too. Updated the countries and corrected a mistake in Sweden. Added Ireland and Irish/Gaelic language 1.1.0 Changed the Language Selection (see details above), added Sweden 1.0.2 Added France and Départements and French Language/Titles 1.0.1 Added Austria and its Bundesländer, Added United Kingdom (England, Northern Ireland, Wales and Scotland) 1.0.0 Initial Version for Switzerland & Germany With all Provinces (Kantone / Bundesländer) Hope you enjoy the scene and some of you can use it Here is the complete .lua file: BankHolidayCalc_V1.2.3a.lua Cheers Don BankHolidayCalc.lua BankHolidayCalc_V1.0.1.lua BankHolidayCalc_V1.0.2.lua BankHolidayCalc_V1.1.0.lua BankHolidayCalc_V1.2.0.lua BankHolidayCalc_V1.2.1.lua BankHolidayCalc_V1.2.2.lua BankHolidayCalc_V1.2.3.lua
  5. Hi, Here is my working Volvo interface. Most things you can do with your Volvo On Call app, you can also read out and do with the following Scene + VD. To start off, it is using the jT.hometable so if you don't use that, start using that or strip it away in the Scene/VD. You need to add a entry in your jT.hometable called 'volvo' an example looks like this (yes all here is dummy data and also the 'time' one) volvo = { sceneid = 14, lua = 512, vin = 'YOURVINNUMBER', auth = 'Basic dsjkh42euwendeh279eynhsfd8o3yg7bo3redgefdhf' } And add this line because it uses it to run every xx minutes, add this to your homeTable too. time = { minute = 59000 , five = 299000 , ten = 599000 } Sceneid will be the number of the scene you will create, the 'YOURVINNUMBER' you can get by going into the technical information in your app (usually settings, then technical information, it will be at the bottom) Your basic auth is just a username:password which is base64 encoded. To keep it simple and also have a nice tool to test out api's, i suggest you install Postman. You can add your credentials here: Then click on update request and find your basic auth line here: Next up create your scene: --[[ %% autostart %% properties %% globals volvoTable --]] local jT = json.decode(fibaro:getGlobalValue("HomeTable")) local volvotrigger = tostring(fibaro:getGlobalValue("volvoTable")); local vapi = '/customerapi/rest/v3.0/vehicles/' local shortUrl = 'https://vocapi.wirelesscar.net/customerapi/rest/v3.0/vehicles/' .. jT.volvo.vin local trigger = fibaro:getSourceTrigger() if (trigger['type'] == 'global') then controlUrl = shortUrl .. "" .. volvotrigger httpmethod = 'POST' else controlUrl = shortUrl .. "/status" httpmethod = 'GET' end local httpClient = net.HTTPClient({timeout=5000}) httpClient:request(controlUrl, { options = { method = httpmethod, headers = { ['Content-Type'] = 'application/json; charset=UTF-8', ['Authorization'] = jT.volvo.auth, ['User-Agent'] = 'Dalvik/2.1.0 (Linux; U; Android 5.1.1; SM-G925F Build/LME47X)', ['X-Device-Id'] = 'b7d2fb2e39436fe', ['X-OS-Type'] = 'Android', ['X-Originator-Type'] = 'app' } }, success = function(status) if (trigger['type'] ~= 'global') then local result = json.decode(status.data) if result then -- print("successful") -- print(status.data) if result.carLocked then fibaro:call(jT.volvo.lua, "setProperty", "ui.Label1.value", "Yes"); else fibaro:call(jT.volvo.lua, "setProperty", "ui.Label1.value", "No"); end fibaro:call(jT.volvo.lua, "setProperty", "ui.Label2.value", result.distanceToEmpty); fibaro:call(jT.volvo.lua, "setProperty", "ui.Label3.value", result.heater.status); fibaro:call(jT.volvo.lua, "setProperty", "ui.Label4.value", result.serviceWarningStatus); print(result.serviceWarningStatus) end else print(status.data) -- failed end end, error = function(error) --errorlog("ERROR") print(error) end }) As you might have noticed it also uses a GlobalVar called "volvoTable" you need to make this one too. You can leave the value empty for now. Now install the VD (yes remember the ID to fill it in the jT table) Volvo_V40.vfib And then make it fancy with a nice picture for the scene: And one for the lua. And if all goes well, you can see this one: There is more you can do, but for now i think this is sufficient. I own a V40 hence why it says that. Some cars don't have preheating or have other features (but these are most common) If it doesn't work, let me know since this is my first 'bigger' scene & vd scripts in lua. It uses the global var to send over the url it needs to post to the api, while status commands are get commands for example. Have fun (this really should be just a proper plugin)
  6. Fetch data from wunderground.com, send morning and afternoon forecast to your smartphone using Fibaro app, Telegram or Pushover. Data from wunderground.com can be from a PersonalWeatherStation(PWS) or nearest LocationID(LOCID) Example of forecast and pushoptions to use. 1'st value is smartphoneID, 2'nd value is morning forecast, 3'rd is afternoon forecast, 4'th is pushoption smartphoneID_and_fcst ={{281, "06:30", "17:00", "Telegram"},{320, "08:00", "17:00", "Pushover"},{32, "08:00", "17:00", "Fibaro"}} Sending as Pushover message requires an own scene that monitors Pushover variable, read about it here: http://forum.fibaro.com/index.php?/topic/17422-tutorial-pushover-lua-vd-global-function/#entry55857 All important keys like API keys, tokens etc will be saved to variable panel. Supports many languages (EN, FR, SW, PL, NL, DE, NO, RO, CZ, GR, PT, RU (default is en)) Complete lua code (save in a new scene) --[[ %% autostart %% properties %% globals --]] ------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------- -- HOWTO -- -- 1. Create a virtual device with 9 labels and set the ID to like below, else this scene will not work. -- 2. lblTemp, lblHum, lblBar, lblWind, lblRain, lblFcst, lblStation, lblUpdate, lblNotify -- 3. Change ID of virtual device in WU.selfId -- FIRST TIME USERS NEEDS TO COPY ALL CODE TO SCENE, after version 2.5.0 it should only be neccessary to update from "UPDATE FROM HERE" text -- NOTE -- -- Scheduled time you set for forecast push is just an indication of time. -- Real time will be the hour you set + minute of when scene starts. -- Script will check server version for new updated version (default = true) -- WU WeatherData - Fetch weather data from wunderground.com. Multilanguage support! -- Inspired by GEA(steven), stevenvd, Krikroff and many other users. -- Source - forum.fibaro.com, domotique-fibaro.fr and worldwideweb -- Special thanks to petergebruers from forum.fibaro.com with demo script -- -- -- PWS = Personal Weather Station -- LOCID = Public station -- -- -- 2014-03-22 - Permissions granted from Krikroff -- 2014-03-23 - Added rain and forecast, Added FR language. -- 2014-03-23 - Language variable changed to get the translation from wunderground.com in forcast -- 2014-03-24 - Added PL language -- 2014-03-24 - Select between PWS or LOCID to download weather data -- 2015-10-23 - New source code. -- 2015-10-23 - Added NL translation -- 2015-11-16 - Added DE, FR translation. Fixed some bug in the code(hardcoded smartphoneID,inch to metric for rain value) -- 2015-11-18 - Script moved to scene instead of mainloop in VD. VD is only used as GUI. -- 2015-11-18 - Send push if script cannot fetch data -- 2015-11-26 - adjustment of code. Function from sebcbien at domotique-fibaro.fr -- 2015-11-27 - Oops! Removed forecast push by mistace. -- 2016-02-11 - send push if new version of script is out -- 2016-03-31 - Added NO translation, did cleanup the code a little bit. -- 2016-03-31 - It is now posible to use Telegram as push. Change WU.pushOption value to Telegram or Fibaro. -- - also change WU.Telegramtoken and WU.Telegramchat_id to your values -- 2016-04-01 - Fixed bug when using Telegram push, forecast must send with lowercases. -- 2016-05-26 - Added support for multiple smartphone id when sending push -- 2016-05-30 - Implemented "UPDATE SECTION" -- 2016-07-13 - Bug fixed some code for sendPush to fibaro app -- 2016-07-14 - Telegram, possible to have forecast pushed to 2 different chat_id's -- 2016-07-15 - Save all importent values to variable. -- 2016-07-15 - Added RO, GR, PT, RU and CZ translation -- 2016-07-16 - Possible to have different time for push to all smartphones -- 2016.07-17 - Bugfixes. Changed layout of JSON table for smartphoneID, time and push option -- 2016-07-18 - Bugfixes and better error reporting. Supports Pushover (works together with -- 2016-07-19 - Bugfixes again. -- 2016-07-22 - Added seconde forcast to both morning and afternoon push message. Added parse_mode for bold telegram text message -- 2016-07-24 - Added ES (Spanish) translation -- 2016-08-03 - Bugfixes (in WU.dualChat_ID part of code) WU = {} versionCheck = true -- check if new version of script exist on server WU.language = "SW"; -- EN, FR, SW, PL, NL, DE, NO, RO, CZ, GR, PT, RU, ES (default is en) ---- UPDATE FROM HERE ---- -- WU settings if not fibaro:getGlobal("WUAPI") == nil then WU.APIkey = fibaro:getGlobal("WUAPI") else -- [CHANGE THIS IF VALUES ARE NOT STORED IN VARIABLE PANEL] WU.APIkey = "14eaffxxxxxxxxxxxxxx" --Put your WU api key here end WU.PWS = "IGVLEBOR5" -- The PWS location to get data for (Personal Weather Station) WU.LOCID = "SWXX0076" -- The location ID to get data for (City location) WU.station = "PWS" -- PWS or LOCID ---- UPDATE FROM HERE ---- version = "{V3.0.5}" -- Other settings smartphoneID_and_fcst ={{281, "06:30", "21:10", "Telegram"},{32, "08:00", "16:00", "Fibaro"}} -- ID, time for morning and afternoon forecast and what push to use WU.sendPush = true -- send forecast with push -- Telegram settings -- IMPORTANT -- -- Telegramtoken needs to splitted into 2 parts. First part1 is before the ":", part2 is after the ":" if not fibaro:getGlobal("Telegramtoken1_part1") == nil then WU.Telegramtoken1_part1 = fibaro:getGlobal("Telegramtoken1_part1") else -- [CHANGE THIS IF VALUES ARE NOT STORED IN VARIABLE PANEL] Telegramtoken needs to splitted into 2 parts. First part1 is before the ":", part2 is after the ":" WU.Telegramtoken1_part1 = "187xxxxxx" -- ******** end if not fibaro:getGlobal("Telegramtoken1_part2") == nil then WU.Telegramtoken1_part2 = fibaro:getGlobal("Telegramtoken1_part2") else -- [CHANGE THIS IF VALUES ARE NOT STORED IN VARIABLE PANEL]Telegramtoken needs to splitted into 2 parts. First part1 is before the ":", part2 is after the ":" WU.Telegramtoken1_part2 = "AAHfzhTcsKloviNxxxxxxxxxxxxxxxxx" -- ******** end if not fibaro:getGlobal("Telegramchat_id1") == nil then WU.Telegramchat_id1 = fibaro:getGlobal("Telegramchat_id1") else -- [CHANGE THIS IF VALUES ARE NOT STORED IN VARIABLE PANEL] Telegramtoken chat_id 1 WU.Telegramchat_id1 = "2025xxxxx" -- ******** end -- If you want forecast to be pushed to a second phone WU.dualChat_ID = false -- set to true if more then 1 smartphone that should have forecast pushed. if not fibaro:getGlobal("Telegramtoken2_part1") == nil then WU.Telegramtoken2_part1 = fibaro:getGlobal("Telegramtoken2_part1") else -- [CHANGE THIS IF VALUES ARE NOT STORED IN VARIABLE PANEL] Telegramtoken needs to splitted into 2 parts. First part1 is before the ":", part2 is after the ":" WU.Telegramtoken2_part1 = "187xxxxxx" end if not fibaro:getGlobal("Telegramtoken2_part2") == nil then WU.Telegramtoken2_part2 = fibaro:getGlobal("Telegramtoken2_part2") else -- [CHANGE THIS IF VALUES ARE NOT STORED IN VARIABLE PANEL] Telegramtoken needs to splitted into 2 parts. First part1 is before the ":", part2 is after the ":" WU.Telegramtoken2_part2 = "AAHfzhTcsKloviNxxxxxxxxxxxxxxxxx" -- ******** end if not fibaro:getGlobal("Telegramchat_id2") == nil then WU.Telegramchat_id2 = fibaro:getGlobal("Telegramchat_id2") else -- [CHANGE THIS IF VALUES ARE NOT STORED IN VARIABLE PANEL]Telegramtoken chat_id 2 WU.Telegramchat_id2 = "2025xxxxx" -- ******** end updateEvery = 5 -- get data every xx minutes WU.selfId = 150 -- ID of virtual device WU.translation = {true} WU.currentDate = os.date("*t"); DoNotRecheckBefore = os.time() WU.scheduler = os.time()+60*updateEvery WU.translation["EN"] = { Exiting_loop_push = "Exiting_loop_push", Push_forecast = "Push forecast", Temperature = "Temperature", Humidity = "Humidity", Pressure = "Pressure", Wind = "Wind", Rain = "Rain", Forecast = "Forecast", Station = "Station", Fetched = "Fetched", Data_processed = "Data processed", Update_interval = "Next update will be in (min)", No_data_fetched = "No data fetched", new_version = "New version of WUWeather.lua script is out! ", script_url = "http://jonnylarsson.se/JL/", NO_STATIONID_FOUND = "No stationID found", NO_DATA_FOUND = "No data found" } WU.translation["FR"] = { Exiting_loop_push = "Exiting_loop_push", Push_forecast = "Push prévisions", Temperature = "Température", Humidity = "Humidité", Pressure = "Pression", Wind = "Vent", Rain = "Pluie", Forecast = "Prévisions", Station = "Station", Fetched = "Reçu", Data_processed = "Données Analysées", Update_interval = "Prochaine update prévue dans (min)", No_data_fetched = "Pas de données reçues", new_version = "New version of WUWeather.lua script is out! ", script_url = "http://jonnylarsson.se/JL/", NO_STATIONID_FOUND = "StationID non trouvée", NO_DATA_FOUND = "Pas de données disponibles" } WU.translation["SW"] = { Exiting_loop_push = "Push loop avslutad", Push_forecast = "Push forecast", Temperature = "Temperatur", Humidity = "Fuktighet", Pressure = "Barometer", Wind = "Vind", Rain = "Regn", Forecast = "Prognos", Station = "Station", Fetched = "Hämtat", Data_processed = "All data processat", new_version = "New version of WUWeather.lua script is out! ", script_url = "http://jonnylarsson.se/JL/", Update_interval = "Nästa uppdatering är om (min)", No_data_fetched = "Inget data hämtat", NO_STATIONID_FOUND = "StationID ej funnet", NO_DATA_FOUND = "Ingen data hos WU" } WU.translation["PL"] = { Exiting_loop_push = "Kończę pętlę PUSH", Push_forecast = "PUSH prognozy", Temperature = "Temperatura", Humidity = "Wilgotność", Pressure = "Ciśnienie", Wind = "Wiatr", Rain = "Deszcz", Forecast = "Prognoza", Station = "Stacja", Fetched = "Nie pobrano danych", Data_processed = "Dane przetworzone", new_version = "Dostępna nowa wersja skryptu WUWeather.lua ! ", script_url = "http://jonnylarsson.se/JL/", No_data_fetched = "Brak danych", Update_interval = "Następna aktualizacja za (min)", NO_STATIONID_FOUND = "Nie znaleziono ID Stacji", NO_DATA_FOUND = "Brak danych" } WU.translation["NL"] = { Exiting_loop_push = "Exiting_loop_push", Push_forecast = "Push verwachting", Temperature = "Temperatuur", Humidity = "Vochtigheid", Pressure = "Druk", Wind = "Wind", Rain = "Regen", Forecast = "Verwachting", Station = "Weerstation", Fetched = "Ontvangen", Data_processed = "Gegevens verwerkt", new_version = "New version of WUWeather.lua script is out! ", script_url = "http://jonnylarsson.se/JL/", Update_interval = "Volgende update in (min)", No_data_fetched = "Geen gegevens ontvangen", NO_STATIONID_FOUND = "Geen stationID gevonden", NO_DATA_FOUND = "Geen gegevens gevonden" } WU.translation["DE"] = { Exiting_loop_push = "Exiting_loop_push", Push_forecast = "Push vorhersage", Temperature = "Temperatur", Humidity = "Luftfeuchtigkeit", Pressure = "Luftdruck", Wind = "Wind", Rain = "Regen", Forecast = "Vorhersage", Station = "Station", Fetched = "Abgerufen", Data_processed = "Daten verarbeitet", new_version = "New version of WUWeather.lua script is out! ", script_url = "http://jonnylarsson.se/JL/", No_data_fetched = "Keine Daten abgerufen", Update_interval = "Das nächste Update in (min)", NO_STATIONID_FOUND = "Keine stationID gefunden", NO_DATA_FOUND = "Keine Daten gefunden" } WU.translation["NO"] = { Exiting_loop_push = "Exiting_loop_push", Push_forecast = "Push værmelding", Temperature = "Temperatur", Humidity = "Fuktighet", Pressure = "Barometer", Wind = "Vind", Rain = "Regn", Forecast = "Prognose", Station = "Stasjon", Fetched = "Hentet", Data_processed = "All data prosessert", Update_interval = "Neste oppdatering om (min)", No_data_fetched = "Ingen data hentet", NO_STATIONID_FOUND = "StasjonID ikke funnet", NO_DATA_FOUND = "Ingen data hos WU" } WU.translation["CZ"] = { Exiting_loop_push = "Exiting_loop_push", Push_forecast = "Push forecast", Temperature = "Teplota", Humidity = "Vlhkost", Pressure = "(Atmosférický) Tlak", Wind = "Vítr", Rain = "Déšť ", Forecast = "Předpověď", Station = "Stanice", Fetched = "Předána", Data_processed = "Data_zpracována", Update_interval = "Časová_prodleva_mezi_aktualizacemi", No_data_fetched = "Data_nebyla_předána", NO_STATIONID_FOUND = "Stanice_nenalezena", NO_DATA_FOUND = "Data_Nenalezena" } WU.translation["RO"] = { Exiting_loop_push = "Exiting_loop_push", Push_forecast = "Prognoza apăsare", Temperature = "Temperatura", Humidity = "Umiditate", Pressure = "Presiune", Wind = "Vant", Rain = "Ploaie", Forecast = "Prognoza", Station = "Statie", Fetched = "Preluat", Data_processed = "Datele prelucrate", Update_interval = "Urmatorul update va fi in (min)", No_data_fetched = "Nu exista date preluate", NO_STATIONID_FOUND = "Nu a fost gasit stationID ", NO_DATA_FOUND = "Datele nu au fost gasite" } WU.translation["GR"] = { Exiting_loop_push = "Exiting_loop_push", Push_forecast = "Πρόγνωση push", Temperature = "Θερμοκρασία", Humidity = "Υγρασία", Pressure = "Πίεση", Wind = "Άνεμος", Rain = "Βροχή", Forecast = "Πρόβλεψη", Station = "Σταθμός", Fetched = "Παραλήφθηκαν", Data_processed = "Επεξεργασμένα δεδομένα", Update_interval = "Η επόμενη ενημέρωση θα γίνει σε (min)", No_data_fetched = "Δεν παραλήφθηκαν δεδομένα", NO_STATIONID_FOUND = "Δεν βρέθηκε το Station ID", NO_DATA_FOUND = "Δεν βρέθηκαν δεδομένα" } WU.translation["PT"] = { Exiting_loop_push = "Exiting_loop_push", Push_forecast = "Previsão do impulso", Temperature = "Temperatura", Humidity = "Humidade", Pressure = "Pressão", Wind = "Vento", Rain = "Chuva", Forecast = "Previsão", Station = "Estação", Fetched = "Procurar", Data_processed = "Dados processados", Update_interval = "Próxima atualização será em (min)", No_data_fetched = "Não foram encontrados dados", NO_STATIONID_FOUND = "Não foi detetada nenhuma estação", NO_DATA_FOUND = "Não foram encontrados dados" } WU.translation["RU"] = { Exiting_loop_push = "Exiting_loop_push", Push_forecast = "Прогноз Нажмите", Temperature = "Температура", Humidity = "Влажность", Pressure = "Давление", Wind = "Ветер", Rain = "Дождь", Forecast = "Прогноз", Station = "Станция", Fetched = "Получено", Data_processed = "Данные обработаны", Update_interval = "Следующее обновление через (мин.)", No_data_fetched = "Данные не получены", NO_STATIONID_FOUND = "Данная станция не найдена", NO_DATA_FOUND = "Данные не найдены" } WU.translation["ES"] = { Exiting_loop_push = "Exiting_loop_push", Push_forecast = "Pronóstico enviado", Temperature = "Temperatura", Humidity = "Humedad", Pressure = "Presión", Wind = "Viento", Rain = "Precipitaciones", Forecast = "Pronóstico", Station = "Estación", Fetched = "Extraído", Data_processed = "Datos procesados", Update_interval = "La próxima actualización será en (min)", No_data_fetched = "Ningún dato extraído", new_version = "Nueva versión del script WUWeather.lua disponible! ", script_url = "http://jonnylarsson.se/JL/", NO_STATIONID_FOUND = "No se ha encontrado la stationID", NO_DATA_FOUND = "Datos no encontrados" } if WU.station == "LOCID" then locationID = WU.LOCID elseif WU.station == "PWS" then locationID = WU.PWS end Debug = function ( color, message ) fibaro:debug(string.format('<%s style="color:%s;">%s</%s>', "span", color, message, "span")); end function log(str) if debug then fibaro:debug(str); end end function errorlog(str) fibaro:debug("<font color='red'>"..str.."</font>") end function Telegrambot(msg) -- Read settings from variable WU.Telegramtoken1 = fibaro:getGlobal("Telegramtoken1_part1")..":"..fibaro:getGlobal("Telegramtoken1_part2") WU.Telegramchat_id1 = fibaro:getGlobal("Telegramchat_id1") WU.Telegramurl1 = "https://api.telegram.org/bot"..WU.Telegramtoken1.."/sendMessage?chat_id="..WU.Telegramchat_id1.."&text=" if WU.dualChat_ID then WU.Telegramtoken2 = fibaro:getGlobal("Telegramtoken2_part1")..":"..fibaro:getGlobal("Telegramtoken2_part2") WU.Telegramchat_id2 = fibaro:getGlobal("Telegramchat_id2") WU.Telegramurl2 = "https://api.telegram.org/bot"..WU.Telegramtoken2.."/sendMessage?chat_id="..WU.Telegramchat_id2.."&text=" end -- End read settings from variable local selfhttp = net.HTTPClient({timeout=2000}) url = WU.Telegramurl1 .. msg selfhttp:request(url, { options={ headers = selfhttp.controlHeaders, data = requestBody, method = 'GET' }, success = function(status) local result = json.decode(status.data); if result.ok == true then Debug("grey", "Sucessfully sent message to Telegram Bot...") else --errorlog("failed"); print(status.data); end end, error = function(error) --errorlog("ERROR") Debug("red", error) end }) if WU.dualChat_ID then url2 = WU.Telegramurl2 .. msg selfhttp:request(url2, { options={ headers = selfhttp.controlHeaders, data = requestBody, method = 'GET' }, success = function(status) local result = json.decode(status.data); if result.ok == true then Debug("grey", "Sucessfully sent message to Telegram Bot...") else --errorlog("failed"); print(status.data); end end, error = function(error) --errorlog("ERROR") Debug("red", error) end }) end end function versionChecker() local function getMethod(requestUrl, successCallback, errorCallback) local http = net.HTTPClient() http:request(requestUrl, { options = { method = 'GET', headers = { }, }, success = successCallback, error = errorCallback }) end content = "WUWeather.lua" local url = 'http://jonnylarsson.se/JL/'..content getMethod(url, function(resp) s = resp.data serverVersion = string.match(s, "{V(.-)}"); scriptVersion = string.match(version, "{V(.-)}"); if serverVersion > scriptVersion then Debug("grey", "Checking script version...") Debug("yellow", "There is a new version out! "..'<a href="http://jonnylarsson.se/JL/WUWeather.lua" target="_blank" style="display:inline;color:Cyan">Get it!</a>') if WU.sendPush then for k,smartphoneID_and_fcst in ipairs(smartphoneID_and_fcst) do if smartphoneID_and_fcst[4] == "Fibaro" then fibaro:call(smartphoneID_and_fcst[1] , "sendPush", WU.translation[WU.language]["new_version"].." "..WU.translation[WU.language]["script_url"]) elseif smartphoneID_and_fcst[4] == "Telegram" then Telegrambot(WU.translation[WU.language]["new_version"].." "..WU.translation[WU.language]["script_url"]) end end end end end, function(err) print('error' .. err) end ) end local http = net.HTTPClient() local function errorWU(err) if WU.pushOption == "Fibaro" then fibaro:call(WU.smartphoneID , "sendPush", "[WUWeather scene]. Error: "..err ) elseif WU.pushOption == "Telegram" then Telegrambot("[WUWeather scene]. Error: "..err ) end Debug( "red", "[HTTPClient:request]. Error: "..err ); end local function sendPopup() -- variable containing path of Motion Sensor’s icon local imgUrl = popupIMG -- pop-up call HomeCenter.PopupService.publish({ -- title (required) title = 'Weather forecast', -- subtitle(optional), e.g. time and date of the pop-up call subtitle = os.date("%I:%M:%S %p | %B %d, %Y"), -- content header (optional) contentTitle = 'Forecast from WU Weather', -- content (required) contentBody = fcastday.." - "..fcast, -- notification image (assigned from the variable) img = imgUrl, -- type of the pop-up type = 'Info', }) end function createGlobalIfNotExists(varName, defaultValue) if (fibaro:getGlobal(varName) == nil) then Debug("cyan", "Creating the variable: "..varName.." with value: "..defaultValue) newVar = {} newVar.name = varName newVar.value = defaultValue local http = net.HTTPClient() http:request("http://127.0.0.1:11111/api/globalVariables", { options = { method = 'POST', data = json.encode(newVar)}}) end end local function processWU(response) http:request("http://api.wunderground.com/api/"..WU.APIkey.."/conditions/forecast/lang:"..WU.language.."/q/"..WU.station..":"..locationID..".json",{ options = {method = 'GET'}, success = processWU, error = errorWU }) Debug( "green", "Now downloading data from www.wunderground.com"); if response then -- the first time you enter the loop, this will be nil jsonTable = json.decode(response.data) if jsonTable.response.error ~= nil then Debug( "red", jsonTable.response.error.description) else jsonTable = json.decode(response.data) WU.now = os.date("%H:%M") stationID = jsonTable.current_observation.station_id city = jsonTable.current_observation.observation_location.city humidity = jsonTable.current_observation.relative_humidity temperature = jsonTable.current_observation.temp_c pression = jsonTable.current_observation.pressure_mb wind = jsonTable.current_observation.wind_kph rain = jsonTable.current_observation.precip_today_metric icon = jsonTable.current_observation.icon weathericon = jsonTable.current_observation.icon_url fcstday1 = jsonTable.forecast.txt_forecast.forecastday[1].title fcst1 = jsonTable.forecast.txt_forecast.forecastday[1].fcttext_metric fcst1icon = jsonTable.forecast.txt_forecast.forecastday[1].icon_url fcstday2 = jsonTable.forecast.txt_forecast.forecastday[2].title fcst2 = jsonTable.forecast.txt_forecast.forecastday[2].fcttext_metric fcst2icon = jsonTable.forecast.txt_forecast.forecastday[2].icon_url fcstday3 = jsonTable.forecast.txt_forecast.forecastday[3].title fcst3 = jsonTable.forecast.txt_forecast.forecastday[3].fcttext_metric fcst3icon = jsonTable.forecast.txt_forecast.forecastday[3].icon_url fcst1_mobile = jsonTable.forecast.simpleforecast.forecastday[1].conditions fcst2_mobile = jsonTable.forecast.simpleforecast.forecastday[2].conditions if (stationID ~= nil) then fibaro:call(WU.selfId , "setProperty", "ui.lblStation.value", locationID); fibaro:call(WU.selfId , "setProperty", "ui.lblCity.value", city); fibaro:call(WU.selfId , "setProperty", "ui.lblTemp.value", WU.translation[WU.language]["Temperature"].." "..temperature.." °C"); fibaro:call(WU.selfId , "setProperty", "ui.lblHum.value", WU.translation[WU.language]["Humidity"].." "..humidity); fibaro:call(WU.selfId , "setProperty", "ui.lblBar.value", WU.translation[WU.language]["Pressure"].." "..pression.." mb"); fibaro:call(WU.selfId , "setProperty", "ui.lblWind.value", WU.translation[WU.language]["Wind"].." "..wind.." km/h"); fibaro:call(WU.selfId , "setProperty", "ui.lblRain.value", WU.translation[WU.language]["Rain"].." "..rain.." mm"); if (WU.now >= "03:00" and WU.now <= "15:59") then fibaro:call(WU.selfId , "setProperty", "ui.lblFcst.value",WU.translation[WU.language]["Forecast"].." "..fcstday1.." - "..fcst1_mobile); --fibaro:call(WU.selfId , "setProperty", "ui.lblIcon.value","<img src=http://jonnylarsson.se/JL/png/"..icon..".png>"); elseif (WU.now >= "16:00" and WU.now <= "23:59") then --fibaro:call(WU.selfId , "setProperty", "ui.lblIcon.value","<img src=http://jonnylarsson.se/JL/png/nt_"..icon..".png>"); fibaro:call(WU.selfId , "setProperty", "ui.lblFcst.value", WU.translation[WU.language]["Forecast"].." "..fcstday2.." - "..fcst2_mobile); end if WU.sendPush then for k,smartphoneID_and_fcst in ipairs(smartphoneID_and_fcst) do if (os.date("%H:%M") == smartphoneID_and_fcst[2]) then if versionCheck then versionChecker() end if smartphoneID_and_fcst[4] == "Fibaro" then fcastday = fcstday1 fcast = fcst1 fibaro:call(smartphoneID_and_fcst[1], "sendPush", fcstday1.." - "..fcst1) popupIMG = "http://jonnylarsson.se/JL/png/"..icon..".png" sendPopup() Debug("grey", "Sucessfully sent push message to "..smartphoneID_and_fcst[1]) elseif smartphoneID_and_fcst[4] == "Telegram" then Telegrambot(fcstday1.."%0A"..string.lower(fcst1).."%0A"..fcst1icon.."%0A".."%0A"..fcstday2.."%0A"..string.lower(fcst2)) elseif smartphoneID_and_fcst[4] == "Pushover" then fibaro:setGlobal("pushoverBody", fcstday1.." - "..string.lower(fcst1).." - "..fcst1icon) end end end for k,smartphoneID_and_fcst in ipairs(smartphoneID_and_fcst) do if (os.date("%H:%M") == smartphoneID_and_fcst[3]) then if smartphoneID_and_fcst[4] == "Fibaro" then fcastday = fcstday2 fcast = fcst2 fibaro:call(smartphoneID_and_fcst[1] , "sendPush", fcstday2.."\n"..string.lower(fcst2).."\n"..fcst2icon.."\n".."\n"..fcstday3.."\n"..string.lower(fcst3)) popupIMG = "http://jonnylarsson.se/JL/png/nt_"..icon..".png" sendPopup() Debug("grey", "Sucessfully sent push message to "..smartphoneID_and_fcst[1]) elseif smartphoneID_and_fcst[4] == "Telegram" then Telegrambot(fcstday2.."%0A"..string.lower(fcst2).."%0A"..fcst2icon.."%0A".."%0A"..fcstday3.."%0A"..string.lower(fcst3)) elseif smartphoneID_and_fcst[4] == "Pushover" then fibaro:setGlobal("pushoverBody", fcstday2.."\n"..string.lower(fcst2).."\n"..fcst2icon.."\n".."\n"..fcstday3.."\n"..string.lower(fcst3)) end end end end if WU.sendPush then fibaro:call(WU.selfId , "setProperty", "ui.lblNotify.value", WU.translation[WU.language]["Push_forecast"].." = true"); else fibaro:call(WU.selfId , "setProperty", "ui.lblNotify.value",WU.translation[WU.language]["Push_forecast"].." = false"); end WU.scheduler = os.time()+updateEvery*60 fibaro:call(WU.selfId, "setProperty", "ui.lblUpdate.value", os.date("%c")); fibaro:debug(WU.translation[WU.language]["Data_processed"]) fibaro:debug(WU.translation[WU.language]["Update_interval"].." "..updateEvery) else fibaro:debug(WU.translation[WU.language]["NO_STATIONID_FOUND"]) end end sleepAndcheck = 0 while sleepAndcheck <= 20*updateEvery do fibaro:sleep(3000) sleepAndcheck = sleepAndcheck+1 for k,smartphoneID_and_fcst in ipairs(smartphoneID_and_fcst) do if (DoNotRecheckBefore <= os.time()) and ((WU.scheduler == os.time) or (os.date("%H:%M") == smartphoneID_and_fcst[2]) or (os.date("%H:%M") == smartphoneID_and_fcst[3])) then fibaro:debug(WU.translation[WU.language]["Push_forecast"]) Debug("orange", WU.translation[WU.language]["Exiting_loop_push"]); DoNotRecheckBefore = os.time()+60 sleepAndcheck = 20*updateEvery end end end end end Debug( "orange", "WU Weather - LUA Scripting by Jonny Larsson 2015/2016" ); Debug( "orange", "Version: "..version); if versionCheck then versionChecker() end createGlobalIfNotExists("WUAPI", WU.APIkey) createGlobalIfNotExists("Telegramtoken1_part1", WU.Telegramtoken1_part1) createGlobalIfNotExists("Telegramtoken1_part2", WU.Telegramtoken1_part2) createGlobalIfNotExists("Telegramchat_id1", WU.Telegramchat_id1) if WU.dualChat_ID then createGlobalIfNotExists("Telegramtoken2_part1", WU.Telegramtoken2_part1) createGlobalIfNotExists("Telegramtoken2_part2", WU.Telegramtoken2_part2) createGlobalIfNotExists("Telegramchat_id2", WU.Telegramchat_id2) end for k,smartphoneID_and_fcst in ipairs(smartphoneID_and_fcst) do Debug( "yellow", "Morning forecast push will be for ID: "..smartphoneID_and_fcst[1].." @ "..smartphoneID_and_fcst[2].." with "..smartphoneID_and_fcst[4]); Debug( "yellow", "Afternoon forecast push will be for ID: "..smartphoneID_and_fcst[1].." @ "..smartphoneID_and_fcst[3].." with "..smartphoneID_and_fcst[4]); end processWU() --this starts an endless loop, until an error occurs ---- END OF UPDATE ----
  7. This is modification of old scene used by many person. I need my modification because of many (biggest or smallest) problem each time when I upgrade HC2 with new firmware and the problem not happen direct after upgrade, but hours or days after (like my last problem with corrupt z-wave databases or 503 error after restart) . I use 2 scenes: First backup-create.lua for create backup with special description. This scene is called by for ex. Main scene for time based events control one time by week. In this scenes You have parameters: backup_symbol = '!' -- this symbol is added on beginning of description on backup time. Scenes use this for identify autobackup and for not delete manual or upgrade time backups (in example on attached printscreen I use ‘p’ on place of '!') backup_stay = '025' -- days for store backup from 001 to 999 days (obligatory with loading zeros). When for ex. you change this parameters for one backup from 030 to 025 and after this return to 030, only this one have different store time from another backups. password = 'cGR1cmJhamxvQGl0LXNlY...' -- your admin name and password coded in base64 ([email protected]:password) portable = { 892 } -- id of iOS devices for popups message The second scene backup-delete.lua is for management of backups. They check if exist any backups with criteria for delete (created by backup-create.lua or with special symbol in description and with put of defined time for store). After check they call function for delete backup. In this scenes You have parameters: backup_symbol = '!' -- most important to be same to backup_symbol defined in backup-create.lua default_stay = 'no' -- use individual backup store time from description. Set 'yes' if you decide to ignore individual time to store backup defined in backup__store.lua and registered in backup description backup_stay = '030' -- if you decide to set default_stay to 'yes' backup_delete.lua use this for check number of day after witch the backup will be delete. The backup_delete.lua use this parameter too for backup with description who start by '!' but without [NNN] for number of store day (ex. for temporary backup created manually, they be delete after this number of day) password = 'cGR1cmJhamxvQGl0LXNlY...' -- your admin name and password coded in base64 ([email protected]:password) I have confirmation from Fibaro Support that "httpClient:request(url..." blocks handle until the scene code is over not only to end of called http work and return results. Because of this and limitation that /api/service/backups/'..id can only be launched once at the same time to delete more than one file, you must call the external scene who delete backups. In this case the delete function is moved from backup-delete.lua code to backup-batch.lua. All necessary parameters are passed automatically to backup-batch.lua, You only need edit parameters in backup-create.lua and backup-delete.lua. I added for batch process NotificationService with popups on web page like in situation with to many scenes run at same time For restore backup when I have 503 error without chance to login I use REST client for POST http://HC2IP/api/service/backups/ with payload {"action":"restore","params":{"id":928}}. "id" I take form GET http://HC2IP/api/service/backups Link for source: https://github.com/dr-boss/hc2-backup Structure of backup description used by scenes: ![025] any character/any text ! - first symbol identify backup created and used by scenes, obligatory for treatment by this two scenes [025] - number of days for store backup, not obligatory, if not exist the backup_stay defined in backup_delete.lua are used.
  8. Universal alarm v1.0 Hello everyone! Here is one simple scene that can be used for FIRE, FLOOD or OTHER ALARM purpose. When triggered by sensor it will send you popup, push and e-mail notification. It can also activate additional alarm sounders. You can also add additional actions to turn On lights, lower blinds or whatever action you like to happen when alarm is breached and also when sensor get back to safe state. There is no global variables needed! If you use HomeTable then you can just uncomment line where this table is read to the scene. SCENE SETUP First you need to decide for what you will use this scene. You can use it for FIRE ALARM or for FLOOD ALARM or for any other purpose that you can think off. Just for setup example I will show here how to set it up for FIRE alarm. Same setup can be done for FLOOD alarm. First you need to add all your smoke detectors to scene header so that it is triggered when any of this sensors detects fire and get breached: --[[ %% properties 96 value 128 value 605 value %% globals --]] Then you can setup devices to which you want this scene to send push notifications. As already mentioned in my other threads, to find ID of your mobile devices you can enter this link in your browser: http://<YOUR_HC_IP>/docs/#!/iosDevices/getIosDevices and then press on button TRY IT! You will get ID numbers of all mobile devices that you can enter here: -- PUSH MESSAGES AND MOBILE DEVICE SETUP --------------------------------- -- define mobile devices to send push messages. Enter devices inside -- braces separated by comma local iosDeviceID = {206, 321}; Then you can setup messages text, translate it to your language: -- PUSH MESSAGES SETUP ------------------------------------------------------ -- enter push message text for breached alarm notification local pushMessage = "WARNING! FIRE/FLOOD/OTHER ALARM BREACHED!"; -- POPUP MESSAGES SETUP ----------------------------------------------------- -- enter popup message text and button caption for breached alarm local popupMainTitle = "FIRE/FLOOD/OTHER ALARM"; local popupTimeFormat = "%H:%M:%S | %d.%m.%Y."; local popupContentTitle = "ALARM breached!"; local popupImgUrl = ""; local popupButtonCaption = "OK"; Here you can setup users that will receive e-mail message. Same as for mobile devices, you can find users ID by entering following link in your browser: http://<YOUR_PC_IP/docs/#!/users/getUserss and then press button TRY IT!. You will get ID numbers of all users that you can enter here: -- E-MAIL MESSAGE SETUP ----------------------------------------------------- -- define users for which you want to receive e-mail warning. Enter users -- inside braces separated by comma local userID = {}; -- Translate this e-mail message text that will be sent to you. On this -- part scene will add which sensor was breached. local emailMessage = "Breached FIRE/FLLOD/OTHER sensor:" In above settings you can also setup first part of the e-mail message. Scene will on that part add room and name of the sensor that is breached! If you want to activate additional sounders because fire and flood sensor sounder is not enough then you can setup here additional sounders to be activated when alarm is activated: -- EXTRA SOUNDER SETUP ------------------------------------------------------ -- define alarm sounder ID inside braces. You can define more than one just -- separate them with comma. local sounderID = {128, 210}; And for the end, if this is not enough for you and you want more action to be executed when alarm is breached, like close water valves, close blinds or turn on some lighting then you can add that code yourself. There are three functions where you can add code: -- EXTRA FUNCTIONS WHERE YOU CAN ADD YOUR CODE ---------------------------- -- use this function to add code that will be executed before all other -- code when sensor is breached function extraUserCodeBreachFirst() -- your code goes here end -- use this function to add code that will be executed after all other -- code when sensor is breached function extraUserCodeBreachLast() -- your code goes here end -- use this function to add code that will be executed when sensor is -- back to safe state function extraUserCodeSafe() -- your code goes here end If you want some action before notifications are send and sounders activated then you add code to function extraUserCodeBreachFirst(). If you want some action to be executed after notifications are sent and sounders activated then you add code to function extraUserCodeBreachLast(). When sensor goes back to safe state scene is activated again. It will not send any messages but will stop sounders and if you want some more action then you can add code to function extraUserCodeSafe(). So, one copy of this scene you can setup for FIRE ALARM. Another copy you can setup for FLOOD ALARM, and if you have something else then you can setup third copy for that OTHER ALARM. NOTE! This scene is tested on my HC2 with software 4.110 by breaching FIRE & FLOOD sensors and found to work flawlessly. If you encounter any problems then please first check your settings and look for typos. If you are still unable to make it work then please send me copy of complete scene code and screenshot of debugging window to my private message and I will help you to make it work! Please, I will appreciate very much any feedback and requests for additional features!! Example of debug window when scene is activated: ICONS DOWNLOAD Icons for this scene you can find here: SCENE DOWNLOAD FILE Please click bellow to download: [SCENE] Universal alarm scene {v1.0} as TXT file --------------------> Universal Alarm scene v1.0.txt [SCENE] Universal alarm scene {v1.0} as LUA file --------------------> Universal Alarm scene v1.0.lua NOTE LUA version of scene code is saved by ZeroBrane Studio v1.50. You can download it at this link: https://studio.zerobrane.com
  9. A while ago, I joined a discussion about controlling a bathroom fan (not a whole house ventilation), by means of a single humidity sensor. This inspired me to clean up my running code and share it with you. VERY IMPORTANT! Only use this script with an Aeotec MultiSensor 6 aka MS6 aka "the square one". I have extensively tested several "MultiSensors" and only MS6 meets its specifications! The older, round MultiSensor and MultiSensor Gen5 have very bad temperature & humidity response (up to 12 percent-point deviation) so they are not good. If I ever find the time, I'll post a calibration procedure and test results of several sensor. I also tested several DIY sensors on a Z-Uno and they can be used as well... but not the old MS! This script uses one, and only one humidity sensor. Because I am convinced, that this is all you need. You can device clever scripts, based on several sensors or weather stations or weather forecast... But in the end this adds complexity and you'll have a hard time convincing me multi-sensor works better! If you want to learn more about my motivation to script it in this particular way, please read: In fact, before I talk about the control scene, I'd like to share script to monitor your setup. It is a script which filters your event log, and puts fan and humidity data in your debug window. The log script enables you to check if the control script runs as expected. The Lua code demonstrates: filtering the event log, sorting data, and outputting data as html or plain text. The log output looks similar to this: Since I took that screenshot I decided it was nicer to reverse the order. If you look at the script you'll see that's only a matter of changing > to < You might notice the fan device has a value... This script can control a fan connected to a dimmer or a switch and the scene automatically detects the difference. I recommend a dimmer only for small fans; < 30 W. For Dimmer 2: set parameter 30 = 0 to force "leading edge control". Features: You can test this script by selecting one dimmer in your house as the "sensor" and another one as the "fan". You can set a parameter to speed up al timers (e.g. turn "minutes" into "seconds") to easy debugging. Requires only one humidity sensor. Can control a fan on a switch or a dimmer. Uses undocumented code, but I guess this is pretty safe to use. Contains lots of comments and lots of debugging. Debugging is easily removed, check comments. Limits fan runtime and does retries. Uses autostart, script recovers from reboot. This scene has not been tested by anyone else, so please run it, check it and share what think, so I can improve it! Note: if you do not have a means to dry your air, which you probably do not have, the control of humidity depends on outdoor conditions. I live in Belgium... According to www.weatheronline.co.uk "The climate of Belgium can be classified as Cfb Climate; a warm temperated humid climate with the warmest month lower than 22°C over average and four or more months above 10°C over average." HC-Log-Humidity-Fan-1.0.0.lua HC-Humidity-Fan-Control-1.0.0.lua
  10. Check status of doors and windows v1.0 This simple scene will send push message every time when door or window is opened if global Variable DoorWinCheck is set to "Yes". Usage, we are sitting in garden on the opposite side of our house main entrance door. Turning this scene on and we will be informed every time when somebody opens main door If scene is started manually with RUN button or by other scene or VD then it will check all doors and windows (or just those we put in the list) and will send popup message with the list of opened doors and windows. The rest is up to you. Here is scene code: --[[ %% properties 125 value 159 value %% globals --]] --[[ --------------------------------------------- -- CHECK DOOR/WINDOWS FOR OPEN/CLOSE STATE -- --------------------------------------------- Copyright © 2016 by Zoran Sankovic - Sankotronic Version 1.0 This scene will be triggered when any door or window is opened or closed if its ID is added above in scene header %% properties section and will send you push notification which one. If it is run manually or started with RUN button or called by VD or other scene then it will check all doors and windows that are added in winDoorID table variable and send you a popup message with the list of all doors and windows openned. This scene requires following global variables: DoorWinCheck - values: "Yes", "No" - set by VD You can enter name of your variable for that purpouse and even map your values to work properly. --]] -- PART OF CODE FOR USERS TO EDIT AND SETUP --------------------------------- -- GLOBAL VARIABLES -- enter names and value mapping of your global variables -- or leave as it is and add to variables panel -- enter name of your global variable and map values local doorWinCheck = "DoorWinCheck"; local doorWinMapping = {Yes="Yes", No="No"}; -- SENSORS, USERS, NOTIFICATIONS setup -------------------------------------- -- enter in this table IDs of all window and door sensors separated by comma -- that you want to be checked when scene is started manually or by another -- scene or VD local winDoorID = {125, 159}; -- define users to send push messages, replace with your user ID local userID = {10, 204, 210}; -- flag for each user; if 1 then send notifications else if 0 do not send notifications local userFlag = {1, 1, 1}; -- setup local variables for notifications -- popup notification title local popupTitle = "Door/Window status"; -- opoup notification subtitle usually contain time when is sent local popupSubtitle = "%H:%M:%S | %d.%m.%Y."; -- message if found any door or window opened local foundOpenedMessage = "Following doors/windows are open:"; -- message if found all doors/windows closed local foundAllClosedMessage = "All doors/windows are closed!"; -- text for button to close popup notification local buttonCaption = "OK"; -- url path to icon to show on popup message local imgUrl = "" -- DEBUGGING VARIABLES --------------------------------------------------- -- setup debugging, true is turned on, false turned off. local deBug = true; -- DEFINE FLAGS - in this section add code to change users flags ----------------- -- END OF CODE PART FOR USERS TO EDIT AND SETUP -------------------------- -- BELLOW CODE NO NEED TO MODIFY BY USER --------------------------------- local OpenWinDoor = ""; local opened = false; local sourceTrigger = fibaro:getSourceTrigger(); local doorWin = fibaro:getGlobalValue(doorWinCheck); -- send push notifications! function sendPush(message) if #userID > 0 then for i = 1, #userID do if userFlag[i] == 1 then fibaro:call(userID[i], "sendPush", message); -- Send message to flagged users end end end end function sendPopup(open, Info) if open then typeInfo = "Warning"; titleInfo = foundOpenedMessage; else typeInfo = "Success"; titleInfo = foundAllClosedMessage; end ------------------------------------- POPUP MESSAGE HomeCenter.PopupService.publish({ -- title (required) title = popupTitle, -- subtitle(optional), e.g. time and date of the pop-up call subtitle = os.date(popupSubtitle), -- content header (optional) contentTitle = titleInfo, -- content (required) contentBody = Info, -- notification image (assigned from the variable) img = "", -- type of the pop-up type = typeInfo, -- buttons definition buttons = { { caption = buttonCaption, sceneId = 0 } } }) end if (sourceTrigger["type"] == "property") then if (doorWin == doorWinMapping.Yes) then local WinDoorID = tonumber(sourceTrigger['deviceID']) local status = tonumber(fibaro:getValue(WinDoorID, "value")) if (status == 1) then local room = fibaro:getRoomNameByDeviceID(WinDoorID); local deviceName = fibaro:getName(WinDoorID); if deBug then fibaro:debug(room..' ' .. deviceName .. ' is opened.') end local pushMessage = room..' ' .. deviceName .. ' is opened.' sendPush(pushMessage); else local deviceName = fibaro:getName(WinDoorID); local room = fibaro:getRoomNameByDeviceID(WinDoorID); if deBug then fibaro:debug(room..' ' .. deviceName .. ' is closed.') end end end elseif (sourceTrigger["type"] == "other") then for i = 1, #winDoorID do if tonumber(fibaro:getValue(winDoorID[i], "value")) == 1 then opened = true; OpenWinDoor = OpenWinDoor .. fibaro:getRoomNameByDeviceID(winDoorID[i]) .." ".. fibaro:getName(winDoorID[i]) .. "\n"; if deBug then fibaro:debug("It is open: "..fibaro:getRoomNameByDeviceID(winDoorID[i]) .." ".. fibaro:getName(winDoorID[i])) end end end if not opened then OpenWinDoor = "All Closed!" end; sendPopup(opened, OpenWinDoor); end fibaro:abort(); global variable DoorWinCheck can be changed by virtual device which have one label and one button. Here is code that goes to button: local selfId = fibaro:getSelfId() -- enter name of your global variable and map values local doorWinCheck = "DoorWinCheck"; local doorWinMapping = {Yes="Yes", No="No"}; if fibaro:getGlobalValue(doorWinCheck) == doorWinMapping.Yes then fibaro:setGlobal(doorWinCheck, doorWinMapping.No) fibaro:call(selfId, "setProperty", "ui.lblDoorWinCheck.value", "No") fibaro:call(selfId, "setProperty", "currentIcon", 402); -- import icon to HC and check ID else fibaro:setGlobal(doorWinCheck, doorWinMapping.Yes) fibaro:call(selfId, "setProperty", "ui.lblDoorWinCheck.value", "Yes") fibaro:call(selfId, "setProperty", "currentIcon", 401); -- import icon to HC and check ID end And if you want you can add this code to Main loop: local selfId = fibaro:getSelfId() -- enter name of your global variable and map values local doorWinCheck = "DoorWinCheck"; local doorWinMapping = {Yes="Yes", No="No"}; if fibaro:getGlobalValue(doorWinCheck) == doorWinMapping.Yes then fibaro:call(selfId, "setProperty", "ui.lblDoorWinCheck.value", "Yes") fibaro:call(selfId, "setProperty", "currentIcon", 401); else fibaro:call(selfId, "setProperty", "ui.lblDoorWinCheck.value", "No") fibaro:call(selfId, "setProperty", "currentIcon", 402); end fibaro:sleep(3000); Don't forget to change name for label from label1 to lblDoorWinCheck or vice-versa. Here is also picture of DV and icons to use for scene and VD: EDIT : New version 1.0 with some changes for users to easier setup. Now you can use existing variable and values you just need to enter name of your variable and map your values to Yes and No for checking and sending push notification when door or window is opened. Also changed push notifications so that users are defined in table variable userID. userFlag defines if user will get notification set by 1, or not set with 0. You can add your part of code to change flags, see example: -- DEFINE FLAGS - in this section add code to change users flags ----------------- local momAway = "MomAway"; local momAwayMapping = {Yes="Yes", No="No"}; if momAway ~= "" then if fibaro:getGlobalValue(momAway) == momAwayMapping.Yes then userFlag[3] = 0; userFlag[4] = 0; end end -- END OF CODE PART FOR USERS TO EDIT AND SETUP -------------------------- Enjoy coding!
  11. Hi guys, I thought to share a simple scene that can be called to trigger any IFTTT action via the Webhooks service. You can call this scene from any other scene or VD just like the smart message hub i.e. fibaro:startScene(sceneID ,{'TriggerID', 'Value1', 'Value2', 'Value3'}) With this you can do pretty much anything IFTTT is capable of. Some examples of what I am using it for below: - Send myself a message from HC2 to my Facebook Messenger - Control my geothermal heatpump (Nibe heatpumps support IFTTT) - Turn on/off main and guest network on the Asus router (also supports IFTTT) But again, you can use this to trigger pretty much any IFTTT applet. Credits: - The logbug function is from Zoran's code (he packs it into all his creations) - fibaro:args() inspired by Frank's smart message hub --[[ %% properties %% events %% globals --]] local deBug = true local args = fibaro:args() local TriggerID local Value1 local Value2 local Value3 local http = net.HTTPClient({timeout=3000}) local Key = '<insert your IFTTT key here>' if args[1] == nil then TriggerID = '' else TriggerID = args[1] end if args[2] == nil then Value1 = '' else Value1 = args[2] end if args[3] == nil then Value2 = '' else Value2 = args[3] end if args[4] == nil then Value3 = '' else Value3 = args[4] end if (fibaro:countScenes() > 1) then logbug('pink', 'The scene is already running') fibaro:abort() end function logbug(color, message) if deBug then for line in message:gmatch("[^\010\013]+") do local txt = line:gsub("([\038\060\062])", function(c) return "&#"..string.byte(c)..";" end) fibaro:debug(('<span style="color:%s">%s</span>'):format(color,txt)) end end end function IFTTTWebhooks() http:request('https://maker.ifttt.com/trigger/'..TriggerID..'/with/key/'..Key, { options={ headers = {['Content-Type'] = 'application/json'}, data = json.encode({value1=Value1, value2=Value2, value3=Value3}), method = 'POST', timeout = 3000 }, success = function(response) logbug('yellow', response.status..' '..response.data) end, error = function(error) print('ERROR: '..error) end }) end IFTTTWebhooks() Edits: added the missing quotation marks (as per @tampiss)
  12. For my grandmother I did a little DIY-project: Incoming calls (via Fritz!Box) are additionally signalled visually by a cheap/simple alarm light combined with a simple actor (i.e. Wall Plug). As long as there's an incoming call, the light is flashing. When the call is accepted or refused or cancelled, it stops flashing. In your Fritz!Box the call monitor has to be enabled and a global variable ("FritzBoxStatus") has to be defined in your HC2. (See German siio.de for further details) --[[ %% properties %% events %% globals FritzBoxStatus --]] -- ######################################################################### -- ## Visual signaling of incoming calls via Fritz!Box (Orgli 2017-12-31) ## -- ######################################################################### -- Call monitor has to be enabled in the Fritz!Box. -- Global variable "FritzBoxStatus" has to be defined. -- Get current status of the Fritz!Box (here: "RING"). local startSource = fibaro:getSourceTrigger(); if ( ( tostring(fibaro:getGlobalValue("FritzBoxStatus")) == "RING") or startSource["type"] == "other" ) then -- Replace "[XX]" with the ID of your actor/device (more devices separated with ",") -- to be turned on. You can also change the action turnOn/turnOff. fibaro:call([XX], "turnOn") else -- Replace "[XX]" with the ID of your actor/device (more devices separated with ",") -- to be turned off. You can also change the action turnOn/turnOff. fibaro:call([XX], "turnOff"); end
  13. Season holiday iscoming so I am happy to share the scene to control the VDs for PHILIPS HUE. That can be used not only for the color lights during holidays, but also for decorative light arrangement in the garden or wherever. The scene is controlling the VDs published by @Sankotronic here : The user settings is very simple. There are three parameters to be entered. 1. timeBRI is the value for the cycle of the brightness change 2. timeHUE is the value for the cycle of the hue cycle 3. lights ={} contain the IDs of the HUE lights to be controlled. I reccomend to experiment with different values and see the result of the "DYNAMIC RAINBOW" with your lights. -- BEGIN OF USER SETTINGS -- time for BRIGHTNESS cycle [ time units depend on number of lights ] local timeBRI = 100 -- time for HUE cycle [ time units depend on number of lights ] local timeHUE = 20 -- IDs of HUE lights VDs to be controlled local lights = {1240,1247,1249,1250,1251,1252,1253}; -- END OF USER SETTINGS The scene is running in the endless loop, so if you want to stop it, you have to press button on the scene icon GUI. DYNAMIC RAIBOW 1.01.txt UPDATE: There are quite interesting result if you run two instances of this scene at the same time :
  14. --- Yamonos 1.0 beta --- -- Automatically turns on a Yamaha Receiver (and switches it to the appropriate input) when a Sonos Connect starts playing. -- It requires a Yamaha Virtual Device that stores the correct power state and input in 2 separate Global Variables -- Known issue: If there are multiple grouped devices, Sonos will keep setting the status to "Playing", even if the devices are paused. -- Feel free to improve it and share it -- adjust the variables section below --[[ %% 526 properties %% 525 properties %% 359 properties %% autostart %% events %% globals --]] local YamahaAVR = 359 -- Yamaha VD ID local sonos = 526 -- Sonos Connect ID local pwrBtn = 1 -- the Yamaha VD button ID to turn on the device local offBtn = 2 -- the Yamaha VD button ID to turn off the device local srcBtn = 8 -- the Yamaha VD source button ID local sleepTime = 5000 -- how often should Fibaro check the AV status - in miliseconds local globalVarName = "YAMAHA" -- global variable name created for Yamaha VD local globalVarInputName = "YAMAHA_SET" -- global variable name for Yamaha VD to set the input local avInput = "AV2" -- The Global variable set by the Yamaha VD local globalVarValueOn = "ON" -- the value of the global variable when ON, set by Yamaha VD local globalVarValueOff = "Standby" -- the value of the global variable when OFF, set by Yamaha VD -------- no input is necessary from here --------------- local executed = false function turnOnYamaha() fibaro:call(YamahaAVR, "pressButton",pwrBtn) --POWER ON fibaro:debug("yamaha on") fibaro:sleep(2000) --wait 2 sec until it turns on fibaro:debug("yamaha av2") fibaro:call(YamahaAVR, "pressButton",srcBtn) --AV2 executed = true end function turnOffYamaha() fibaro:call(YamahaAVR, "pressButton",offBtn) --POWER OFF fibaro:debug("yamaha off") end while true do local sonosPlaying = fibaro:getValue(sonos, "state") local yamahaStatus = fibaro:getGlobalValue(globalVarName) if yamahaStatus == globalVarValueOff and sonosPlaying == "PLAYING" then fibaro:debug("Sonos Playing, Yamaha Off - Turning On Yamaha") if not executed then turnOnYamaha() end executed = false sonosPlaying = fibaro:getValue(sonos, "state") yamahaStatus = fibaro:getGlobalValue(globalVarName) elseif yamahaStatus == globalVarValueOn and sonosPlaying == "PLAYING" then fibaro:debug("Sonos Playing, Yamaha On - Nothing here for me") fibaro:debug(sonosPlaying) sonosPlaying = fibaro:getValue(sonos, "state") yamahaStatus = fibaro:getGlobalValue(globalVarName) elseif sonosPlaying == "PAUSED_PLAYBACK" and yamahaStatus == globalVarValueOff then fibaro:debug(yamahaStatus) fibaro:debug("Sonos Off, Yamaha Off - nothing to do") sonosPlaying = fibaro:getValue(sonos, "state") yamahaStatus = fibaro:getGlobalValue(globalVarName) elseif yamahaStatus == globalVarValueOn and sonosPlaying == "PAUSED_PLAYBACK" then fibaro:debug("Sonos Off, Yamaha On - Turning Off Yamaha") local otherInput = fibaro:getGlobalValue(globalVarInputName) if otherInput ~= (avInput) then fibaro:debug("Yamaha is on another input, do not touch") else turnOffYamaha() end sonosPlaying = fibaro:getValue(sonos, "state") yamahaStatus = fibaro:getGlobalValue(globalVarName) end fibaro:sleep(sleepTime) end Hey Folks, I wrote this small script to help me out with my Sonos Connect and Yamaha AV Receiver. It turns on the Yamaha AV and switches to the correct input as soon as Sonos Connect is playing. It's not perfect, but it works pretty well. Please feel free to improve it, if it's needed. /Seb
  15. Hi everyone. I have few devices that don't react properly to simple "turnOn", "turnOff" actions. Might be Z-wave unresponsive at that time or RF interference or they're too far away from controller or they'e dead. Anyhow when executing fibaro:call(devID,"turnOn") the device doesn't always turning ON (same case for OFF). This phenomena very frustrating especially on predefined events that don't act as expected ( like turn on Fan in bathroom when humidity high, close garage if no presence detected at home, turn on/off water heater according to temperature and etc.) Attached scene code is verifying that the device is not dead, command transferred to device and device has changed the state. In case of problem email sent to notify about problem. In addition I have found that this scene is very efficient to identify unresponsive Z-wave situation and I'm using this scene to turn on/off some device every hour just to see if Z-wave is OK. Some basic instructions: 1. Create new LUA scene and copy attached code in it. 2. Scene call syntax: fibaro:startScene(sceneID, {devID, "turnOn"}) - same parameters as original fibaro:call() That's all for basic. In addition there are two options: 1. If you have device that you want to be notify by email at any time that the device state has been changed (in my case garage gate and water heater), please add third Boolean parameter: fibaro:startScene(sceneID, {devID, "turnOn", true}). You will receive an email one every state change of the device. Could be changed into push notification. 2. If you need to receive scene status of the action or debug information, please follow next instructions: Add "predefined global variable" by name jCall. In order to receive correct response you need to make sure that the scene is executed before that, so the suggested scene call is: fibaro:startScene(sceneID,{devID,"turnOff"}) x=os.time(); while (fibaro:countScenes(sceneID)>0 and os.time() - x < 10) do end jFc = json.decode(fibaro:getGlobalValue("jCall")) fibaro:debug(jFc.resp) -- print debug information if (jFc.status == 1) then -- success - write your code else -- action failed write your code end Note: In case the device already at the same state, email sent to notify that the device state is the same and no action performed. Scene Code below and attachment FibaroCall.rtf local jK,jC = {"device","act", "sEmail"} , {device = -1, act = "noAct", sEmail=false} for i, v in ipairs(fibaro:args(1)) do jC[jK[i]] = v end local actState = {"OFF", "ON", "turnOff" , "turnOn"} local sceneStart = os.time() local log, mLine = "", "————————————————————————————" local mStr = fibaro:getRoomNameByDeviceID(jC.device) ..":" .. fibaro:getName(jC.device) local iVal, iValTime = fibaro:getValue(jC.device, "value"), os.time() - fibaro:getModificationTime(jC.device,"value") local jF = {status=-1,resp="in scene"} if (actState[iVal+3] == jC.act ) then jF.status=1 jF.resp = "<font color=lightblue><sub>" .. fibaro:countScenes() .."</font></sub><font color=yellowgreen>" .. jC.device..":</font><font color=wheat>" .. mStr .. " <font color=lightgreen> [ Device state: " .. actState[iVal+1] .. " | Action: " .. jC.act .. " ] </font><font color=lightblue>-> No actions</font><span style=text-align:center>" if (jC.sEmail == true ) then fibaro:call(2, "sendEmail",fibaro:getName(jC.device) .. ":" .. jC.act , "{ " .. mStr .. " } device at same state as requested:\n" .. mLine .. "\n\t\tDevice state: " .. actState[iVal+1] .. "\n\t\tAction: " .. jC.act .. "\n" .. mLine .. "\n\n☛ Fail-safe Call (•‿•) " ) jF.resp = jF.resp .. " <small>(eMail sent)</small>" end fibaro:debug(jF.resp) if (fibaro:getGlobalValue("jCall")) then fibaro:setGlobal("jCall",json.encode(jF)) end fibaro:abort() end for i=1,3 do fibaro:call(jC.device, jC.act) x = os.time(); while (log == "" and (os.time() - x) < 10) do fibaro:sleep(150) -- time to update log (status) log = fibaro:getValue(jC.device, "log") end fibaro:sleep(350) if (log == "" ) then log="Transfer_was_Blank" end jF.resp = "<font color=lightblue><sub>" .. fibaro:countScenes() .. "</font></sub><font color=grey><sup>" .. i .. "</sup></font><font color=yellowgreen>" .. jC.device..":</font><font color=wheat>" .. mStr .. " <font color=lightgreen> [Action: " .. jC.act .. "] [State: " .. iVal .. ">" .. fibaro:getValue(jC.device, "value") .."]</font> [<small>" .. log .. "</small>]</font>" if (string.find(log,"Transfer_was_") == nil) then if (log == "SEND_COMMAND_TO_DEAD_DEVICE") then jF.resp = jF.resp .. "<br><font color=orangered>Trying " .. jC.act .. " on DEAD device [ " .. mStr .. " ]</font>" fibaro:call(1, 'wakeUpAllDevices',jC.device) end elseif (iVal == fibaro:getValue(jC.device, "value") ) then else jF.status = 1 break end fibaro:debug("<font color=yellowgreen>" .. jC.device.."</font> " .. jF.resp .. " <font color=orangered><small>FAILED</font>" .. "<small> Retry in " .. (.5*i) .. " Sec.</small>") fibaro:sleep(500*i) end -- for i=1,3 do if (jF.status == 0) then jF.resp = "<font color=orangered>Z-Error: </font>" .. jF.resp .. " <small>(eMail sent)</small>" fibaro:call(2, "sendEmail","Z-Error:" .. fibaro:getName(jC.device), "\n{ " .. mStr .. " } does not respond properly!\n" .. mLine .. "\n\t" .. jC.device .. ":" .. fibaro:getName(jC.device) .. " [ " .. actState[iVal+1] .. " > " .. actState[tonumber(fibaro:getValue(jC.device, "value"))+1] .. " ] [ " .. log .. " ]\n\t" .. actState[iVal+1] .. " state duration = " .. os.date("!%H:%M:%S",iValTime) .. " Sec.\n" .. mLine .. "\n\n☛ Fail-safe Call ( ◉︵◉ )") elseif (jC.sEmail == true ) then fibaro:call(2, "sendEmail",fibaro:getName(jC.device).. ":" .. jC.act , "\n{ " .. mStr .. " } device state has been successfully changed.\n" .. mLine .. "\n\t" .. jC.device .. ":" .. fibaro:getName(jC.device) .. " [ " .. actState[iVal+1] .. " > " .. actState[tonumber(fibaro:getValue(jC.device, "value"))+1] .. " : " .. log .. " ]\n\t" .. actState[iVal+1] .. " state duration = " .. os.date("!%H:%M:%S",iValTime) .. " Sec.\n" .. mLine .. "\n\n☛ Fail-safe Call (•‿•) ") jF.resp = jF.resp .. " <small>(eMail sent)</small>" end --if (status == 0) fibaro:debug(jF.resp .. "<small> in " .. os.time() - sceneStart .. " sec. </small><span style=text-align:center>") if (fibaro:getGlobalValue("jCall")) then fibaro:setGlobal("jCall",json.encode(jF)) end
  16. I made a simple standby killer I'd like to share because it might be useful for someone else. The scene is triggered by a delay if house (or room is set to sleep state, I use @Sankotronic Main scene: and my alarm scene: ) But the scene is simple enough to rewrite to your own setup The file: Standby killer.lua On my todo list for this scene: - Add my fire alarm scene ( in case of fire turn off devices) - Add to my room state or main house state VD And looking to @TRicky who I still own a beer for the Hue-bloom icons to make a "Killer" standby killer Icon Jim
  17. I came to share my overflow sensor after the trigger, turn off the faucet, RGBW will blue light, red flash. --[[ %% properties 1671 value %% events %% globals --]] --1671 overflow --1633 Switch valve --1637 RGBW alarm =tonumber(fibaro:getValue(1671, "value")) fibaro:debug(alarm) if(alarm>0) then while(1==1) do fibaro:debug('触发') fibaro:call(1633,"turnOff") fibaro:call(1637, "turnOn") fibaro:call(1637, "setB", "255") fibaro:sleep(500) fibaro:call(1637, "turnOff") fibaro:call(1637, "setR", "255") fibaro:sleep(500) fibaro:call(1637, "turnOff") no_alarm =tonumber(fibaro:getValue(1671, "value")) if(no_alarm==0) then fibaro:call(1637, "turnOff") fibaro:call(1633,"turnOn") break end end else fibaro:debug('不触发') fibaro:call(1637, "turnOff") fibaro:call(1633,"turnOn") end
  18. Hi, Here is a stripped down LUA port of the SunCalc JavaScript library by Vladimir Agafonkin (@mourner) https://github.com/mourner/suncalc I've done some minor modifications to the code, mainly due to the fact that the original functions returned the result in radians. Also, the result was negative or positive relative to the South direction, so I converted it to heading in degrees: 0 - North, 90 - East, 180 - South, 270 - West. I've ported just the azimuth and elevation computation (for now). The scene updates 2 simple global variables (must be created first, names can be changed), and based on these variables, scenes can be triggered, or a VD can display the data. Tested by entering Vladimir's data (see test.js) and by knowing that today at 13:26 was solar noon at my location (180° azimuth at that time - see attached picture). I use this scene to drive my sunshades through the day when is hot outside --[[ %% autostart %% properties %% events %% globals --]] --[[ Scene for computing solar azimuth and elevation, based on SunCalc project https://github.com/mourner/suncalc Copyright (c) 2014, Vladimir Agafonkin All rights reserved. --]] local refreshRate = 60 -- update rate in seconds local azimuthVar = 'solarAzimuth' local elevationVar = 'solarElevation' local debug = true local locationInfo = api.get('/settings/location') print('Location: ' .. locationInfo.city) print('Latitude: ' .. locationInfo.latitude) print('Longitude: ' .. locationInfo.longitude) print() local PI = math.pi local sin = math.sin local cos = math.cos local tan = math.tan local asin = math.asin local atan = math.atan2 local acos = math.acos local rad = PI / 180 local dayMs = 1000 * 60 * 60 * 24 local J1970 = 2440588 local J2000 = 2451545 local e = rad * 23.4397 -- obliquity of the Earth function toJulian(timestamp) return timestamp / dayMs - 0.5 + J1970 end function fromJulian(j) return (j + 0.5 - J1970) * dayMs end function toDays(timestamp) return toJulian(timestamp) - J2000 end function rightAscension(l, b) return atan(sin(l) * cos(e) - tan(b) * sin(e), cos(l)) end function declination(l, b) return asin(sin(b) * cos(e) + cos(b) * sin(e) * sin(l)) end function azimuth(H, phi, dec) return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)) end function elevation(H, phi, dec) return asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)) end function siderealTime(d, lw) return rad * (280.16 + 360.9856235 * d) - lw end function solarMeanAnomaly(d) return rad * (357.5291 + 0.98560028 * d) end function eclipticLongitude(M) local C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)) -- equation of center local P = rad * 102.9372 -- perihelion of the Earth return M + C + P + PI end function sunCoords(d) local M = solarMeanAnomaly(d) local L = eclipticLongitude(M) return { dec = declination(L, 0), ra = rightAscension(L, 0) } end local SunCalc = {} SunCalc.getPosition = function (timestamp, lat, lng) local lw = rad * -lng local phi = rad * lat local d = toDays(timestamp) local c = sunCoords(d) local H = siderealTime(d, lw) - c.ra return { azimuth = azimuth(H, phi, c.dec) * 180 / PI, elevation = elevation(H, phi, c.dec) * 180 / PI } end local pos = {} while true do pos = SunCalc.getPosition(os.time() * 1000, locationInfo.latitude, locationInfo.longitude) fibaro:setGlobal(azimuthVar, string.format('%.2f', pos.azimuth + 180)) fibaro:setGlobal(elevationVar, string.format('%.2f', pos.elevation)) if (debug) then print('Azimuth: ' .. string.format('%.2f', pos.azimuth + 180) .. '°') print('Elevation: ' .. string.format('%.2f', pos.elevation) .. '°') end fibaro:sleep(refreshRate * 1000) end
  19. Hello all, I'd like to share the way I set my alarm powered by Fibaro door/ window -sensors and Motion detectors. I use a scene to call this scene. I hope to provide future reference how to run it otherwise. I'm using @Sankotronic scenes so Globals are based on his code I wrote this scene the @Sankotronic way, easy to use and easy to use in more than one way. I use this basic scen to arm the house when we are away and when we go to bed. At the moment I'm writing a scene that checks open zones (door/ windows not closed, breached motion detectors). When done it 'll be added here. I set up some delay times to arm. Like presentState: I use https://joaoapps.com/ autoremote, autolocatin and join to geofens my and my wifes location to set "PresentState" to "Home" or "Away". So enjoy coding and please if there is a way to make my scene's more effective: correct me!! Jim SetHouseAlarm.lua
  20. Like many others here, I'm frequently plagued by periodic crashes and 503 errors. In my case, I noticed that the memory usage would increase dramatically, to the point where scenes would no longer run, and the web interface wouldn't respond. Only a restart would fix it. I traced it to what I can only think is a memory leak, and I have a suspicion that it's related to the Heating/Cooling Panels. It might be fine for a while, and then for a week or so, I'll get the memory leak problem occur again. I can't be 100% sure, but I'm coming to conclusion that this happens after I've updated the Heating Panel. So I wrote this scene to monitor the memory usage and to automatically reboot the HC2 if the usage exceeds a specified value. I also have it writing the memory usage values off to AllThingsTalk, so that I can see the history, like this: For more details of AllThingsTalk, then see this post: Topic 21656 (Recording Data to AllThingsTalk.IO) Disclaimer: Only use this scene if your system is generally stable but occasionally has a memory problem, otherwise you might send your system into a continuous reboot loop. Please use this scene at your own risk. Only use it if you know what you are doing. Memory Monitor.lua --[[ %% properties %% events %% globals fiveMinuteTimer --]] -- Scene : Memory Monitor -- Version : 1.6 -- Date Created : 16 May 2016 -- Last Changed : 16 May 2017 -- HC Version : Home Center 2 v4.080 -- Created By : Dave Harrison -- Purpose : To keep an eye on the memory usage. -- : When it increases beyond a certain limit, then send a message and reboot the machine. -- : Record data to allthingstalk.io -- Trigger : Triggered by the fiveMinuteTimer global variable --================================================= -------- Declaration: Local Variables --================================================= local debug = true local sourceTrigger = fibaro:getSourceTrigger() local currentDateISO = os.date("!%Y-%m-%dT%XZ") local memoryUsedLimit = 70 local notificationDevice = 266 -- Change this to the mobile device number to send the notification to local allThingsTalkClientID = "xxxxxxxx" -- Change this to your AllThingsTalk ClientID local allThingsTalkClientKey = "yyyyyyyyy" -- Change this to your AllThingsTalk ClientKey local allThingsTalkAssetId = "789b2783e3dfe27040c84833" -- Change this to the Id of the AllThingsTalk Asset that is being used to record the usage --================================================= -------- Functions --================================================= local function log(str) if debug then fibaro:debug(str); end; end local function errorlog(str) fibaro:debug("<font color='red'>"..str.."</font>"); end local function processResponse(response) local memory = response.memory if (memory ~= nil) then local memoryFree = memory.free local memoryCache = memory.cache local memoryBuffers = memory.buffers local memoryUsed = memory.used local memoryTotalUsed = 100 - memoryFree -- Send the memory utilisation to AllThingsTalk local requestData = {value = memoryTotalUsed, at = currentDateISO} local requestBody = json.encode(requestData) sendData(allThingsTalkAssetId, requestBody) if (memoryTotalUsed > memoryUsedLimit) then fibaro:call(notificationDevice, "sendPush", "HC2 memory utilisation is " .. memoryTotalUsed .. "%") errorlog("Memory utilisation is too high: " .. memoryTotalUsed .. "%") -- Reboot the HC2 HomeCenter.SystemService.reboot() else log("Free memory is: " .. memoryFree .. "% Cache: " .. memoryCache .. "% Buffers: " .. memoryBuffers .. "% Used: " .. memoryUsed .. "% Total Used: " .. memoryTotalUsed .. "%") end else errorlog("Memory usage not found in diagnostics API") end end local function processError() errorlog("Error calling diagnostics API") end function sendData (assetId, requestBody) local url = "https://api.allthingstalk.io/asset/" .. assetId .. "/state" local httpClient = net.HTTPClient({timeout=5000}) local httpHeaders = { ["Auth-ClientId"] = allThingsTalkClientID, ["Auth-ClientKey"] = allThingsTalkClientKey, ["Content-Type"] = "application/json", } httpClient:request(url, { options={ headers = httpHeaders, data = requestBody, method = 'PUT', timeout = 5000 }, success = function(response) if (response.status >= 200 and response.status < 300) then log(assetId .. ": " .. response.status .. " - successful") else errorlog(assetId .. ": " .. response.status .. " - ERROR") end end, error = function(error) errorlog(assetId .. ": " .. "ERROR") log(error) end }) end --================================================= -------- Main --================================================= -- Get the memory and CPU usage information response, returnCode = api.get("/diagnostics") if (response ~= nil and returnCode == 200) then processResponse(response) else processError() end If you don't want to mess around with setting up AllThingsTalk, then here is a second version without this functionality: --[[ %% properties %% events %% globals fiveMinuteTimer --]] -- Scene : Memory Monitor -- Version : 1.6 -- Date Created : 16 May 2016 -- Last Changed : 16 May 2017 -- HC Version : Home Center 2 v4.080 -- Created By : Dave Harrison -- Purpose : To keep an eye on the memory usage. -- : When it increases beyond a certain limit, then send a message and reboot the machine. -- Trigger : Triggered by the fiveMinuteTimer global variable --================================================= -------- Declaration: Local Variables --================================================= local debug = true local sourceTrigger = fibaro:getSourceTrigger() local currentDateISO = os.date("!%Y-%m-%dT%XZ") local memoryUsedLimit = 70 local notificationDevice = 266 -- Change this to the mobile device number to send the notification to --================================================= -------- Functions --================================================= local function log(str) if debug then fibaro:debug(str); end; end local function errorlog(str) fibaro:debug("<font color='red'>"..str.."</font>"); end local function processResponse(response) local memory = response.memory if (memory ~= nil) then local memoryFree = memory.free local memoryCache = memory.cache local memoryBuffers = memory.buffers local memoryUsed = memory.used local memoryTotalUsed = 100 - memoryFree -- Send the memory utilisation to AllThingsTalk local requestData = {value = memoryTotalUsed, at = currentDateISO} local requestBody = json.encode(requestData) if (memoryTotalUsed > memoryUsedLimit) then fibaro:call(notificationDevice, "sendPush", "HC2 memory utilisation is " .. memoryTotalUsed .. "%") errorlog("Memory utilisation is too high: " .. memoryTotalUsed .. "%") -- Reboot the HC2 HomeCenter.SystemService.reboot() else log("Free memory is: " .. memoryFree .. "% Cache: " .. memoryCache .. "% Buffers: " .. memoryBuffers .. "% Used: " .. memoryUsed .. "% Total Used: " .. memoryTotalUsed .. "%") end else errorlog("Memory usage not found in diagnostics API") end end local function processError() errorlog("Error calling diagnostics API") end --================================================= -------- Main --================================================= -- Get the memory and CPU usage information response, returnCode = api.get("/diagnostics") if (response ~= nil and returnCode == 200) then processResponse(response) else processError() end The scene is triggered every 5 minutes by a global variable. See Topic 24789 (Simple Timer/Scheduling Scene) or Topic 23510 (Main Scene for Time Based Events Control) for examples of how use a timer global variable. The scene is currently set to reboot when the memory usage exceeds 70%. There is still the possibility that if the memory usage is increasing at a very high rate, then the HC2 will crash before the scene next runs. So setting it to 70% seems to be low enough to catch most instances. Do not set this to a low value otherwise your HC2 might go into a continuous reboot loop. Take a look at your normal RAM usage in the Diagnostics Panel and use a value higher than this. You will need to change the line of code that specifies the Mobile Device Id which should receive the notification message when the memory limit is exceeded. You can find the device id from the API. Enter the following URL into a browser: http://<HC2 IP Address>/api/iosDevices This will return a list of the mobile devices and you can select the appropriate one. You'll also need to assign the correct values to the AllThingsTalk ClientID, ClientKey and AssetId if you're using the first version of the scene. You can get all these values from the Maker pages of AllThingsTalk.com.
  21. Hi All, I'm trying to setup a very simple scene: Requirements: At 20:18 AND when Magnet contact is safe lock door When I configure this in a block scene it doesn't work. It ignores the time trigger and it is immediately closing the lock. What am I doing wrong or is this a bug in Hc2 4.110? Cheers, Landshark EDIT 15/05/17 Unticking the DC Voordeur box as triggering device resolved the problem
  22. Hi, I have been tinkering with my own schedulers for some time now. I know that there are many good examples out there like GEA but I like to write my own code - easier to debug that way . The reason I post here is that I would like to share my experience and code for anyone that wants to play with it. Maybe it can inspire someone to create something more useful for the community...? I'm continuously being inspired and learning things from this community, thanks! Current version: JSched_0_98.lua Warning1: Using this code is on own risk, it is not easy and there are millions of ways to make mistakes. Just getting the json syntax correct after a glass of wine is a challenge If you want an "automated home" instead of a "programmable home" I really recommend purpose built scenes from Sankotronic, Jompa etc... To use this some coding skills (way of thinking) is required - I've written the code and I still make mistakes defining rules I couple of goals with this project; to implemented the rules in json, just because that gives an easy text representation of rules and I had some ideas about composing and pushing rules from an external client. Maybe an easy table in Excel with days and hours and actions that's pushed to the HC2 remote, or actions defined in google calendar.. Haven't implemented that but have grown fond of json anyway... to be expressive enough so that I could fold all my other scenes into one scene and set of rules. That I have done now. to both have timer based rules (classic scheduler) and immediate trigger rules (e.g. device events) and to run them in the same scene instance allowing them to share local scene data. I know GEA allows for both but I'm not sure one can share local data (possible?). HC2 spawns a new scene instance for each event so some trickery is needed. I think I solved that. This means that scenes that typically needed a global variable to synchronize between events or states now can just use local variables in the scene. it can be tested and run from ZeroBrane studio with FibaroSceneAPI (Thanks to petergebruers for fixing the bugs). From ZeroBrane, triggers do not work but can be simulated by queuing up events or from the console. There isa limited complete offline mode. See variables in the beginning of the scene (_remote and _offline) and an engine to play with use cases. My goal is to find some way to abstract templates for typical use cases that could be compiled to run as rules.... It is still under development (templates, better debugging, state-machine format? etc.) but the reason I post now is that it currently runs what I did in all my old scenes. I will continue to update it as it progress. Good ideas are welcome! Disclamer2: I'm not sure I have tested all parts of my code as I mostly run my own rules, e.g. there are bugs for sure. It may lack some obvious commands (RGB) etc. because I don't have these devices. However, it is easy to add, see below. The format for a rule is a json array on toplevel [<expr1>, <expr2>, <expr3>, ..., <expr_n>] each <expr> is evaluated from left to right and stops if an <expr> return false. Typically the leftmost expressions tests if some conditions are true and the rightmost carry out the actions that should happen in that case. A generic <expr> is a json value/pair of format: {COMMAND:<expr1>, &PARAMETER2:<expr2>, &PARAMETER3:<expr3>, ...} <expr1> is the implicit first parameter/argument to the command. Ex. {'push':['$phone.tom','$phone.mary'], '&msg':'Hello'} Arguments can be json arrays for many commands. A json string that starts with '$ is interpreted as a variable. Variables are defined outside the rules with the lua function: defvar(name,value,index) Ex. defvar("phone",{tom='5784582358', mary='565767788'}, true) defvar("room1",{lamp=42}, true) defvar("toilet",{lamp=55, sensor=66}, true) defvar("test",{x = 0}, true) the value can be arbitrary deep ex. 'house.floor.room.lamp'. A common root like with homeTable/JTable also works well. the 'index' parameter makes a reverse map so given the value the variable can be found, and allows the debugging to show the variable name instead of just the value. '$phone.tom' is a 'macro' that expands to {'var':'phone.tom'}, an expression returning the variables value Similar '@var' expands to {'glob':'var'}, which accesses a global variable e.g. fibaro:getGlobal('var') Variables are auto created at first use in an json expr if not already defined with defvar. Many commands are tests and return true/false Ex. {'and':[{'on?':'$room1.lamp'},{'>',[{'last':'$room1.lamp'},{'*':[60,60,3]}]}]} This tests if the lamp in room1 has been on for 3 hours , can also be expressed as {'id':'$room1.lamp', '&value>':0, '&last>':'!60*60*3'} The 'id command accepts a single device or an array of devices and a optional number of tests The example also introduces '!macros, The are some json string on the format '!TEXT' that expands to expressions, which is more convenient than writing the full json expression. '!$test.x=$test.x+1' expands to {'set':{'var':'test.x}, '&val':{'+':[{'var':'test.x'},1]}} '[email protected][email protected]+5' expands to {'set':{'glob':'test.x}, '&val':{'+':[{'glob':'test.x'},5]}} '==' is used to test equality '[email protected]==Night' expands to {'==':[{'glob':'timeofday'},'Night']} '![10:00]' expands to {'time':36000}, that returns true if it is 36000/60 minutes since midnight, e.g if it is 10 o'clock. '![07:50,11:33]' expands to a similar {'time':[...,...]} testing if time is between 7:50 and 11:33.. there is also a "bracketed" time test, '![05:00,$Sunrise,07:00]' that test for the middle time but not sooner than the leftmost and not later than the rightmost. Of course you can use expressions/variables etc that evaluates to seconds of the day. In fact !'!10:00' is just a macro expanding to seconds Standard rules that are run on specific intervals are declared: rule(<optional interval,><json array with expressons><,optional substitution table>) Ex. rule("[{'id':'$toilet.lamp', '&value>':0, '&last>':600},{'id':'$toilet.sensor', '&value<':1, '&last>':600}, {'off':'$toilet.lamp'}, {'log':'Turning toilet lamp off'}]") This decalares a rule that runs with the default 60s interval. It first checks if the lamp is on and has been on for 600s, if not it stops. Else it checks if the movement sensor is off and has been off for 600s. If that is true it continues to run the commands that turn off the lamp and log a statement to the fibaro console. A rule to be run every 5 seconds is declared; event(5,"[... ]"). Many rules that run on different intervals can co-exist. There are also trigger rules. trigger("{ID:PROPERTY}",<json rule><,optional substitution table>) Ex. trigger("{'value':331}","[{'on?':'$toilet.sensor'}, {'off?':'$toilet.lamp'}, {'on':'$toilet.lamp'}, {'log':'Turning on toilet lamp'}]") Assuming that 331 is the id of the toilet sensor. So the trigger syntax is "{'value':331}". Predefined $vars are allowed too, ex. "{'value':'$room1.lamp'}" To invoke this rule, '331 value' must be declared in the scene header (as normal is done) for the scene to receive the event. Implementation detail: The first instance of the scene runs the scheduler of standard rules and normally never terminates. Additional instances of the scene starts when it triggers on incoming events declared in the scene header. For now it supports sourcetriggers that are values, globals, CentralSceneEvents, and SceneEvents. It then uses a shared global (that is autocreated) to hand the event over to the first scene instance so that the declared trigger rule can be run in that context sharing local variables. It uses a simple read/write flag model to handle syncronization and I have stress tested it and have seen no race conditions. However, it is best to set a high number of allowed instances for the scene to be on the safe side. The method introduces a small delay (average 250ms) on events. Many events triggered at the same time may also cause additional small delays. However, to have these two programming models (polling and triggering) converge in one scene instance is worth it... I will implement more types of events in the future. Planning to buy a Fibaro keyfob to play with that new event format... So the normal time testing commands test against minutes. Ex. event("['![10:00]',...]") and because that example runs at the default interval every 60s, it works very well. However, if the rules run more often i.e. event(30,"['![10:00]',...]") the rule will trigger twice the first minute 10'oclock. To avoid this there is a 'once' command, {'once':'![10:00]'} (shortened in macros to '!^[10:00]') that only returns true if the value has changed since last time. This is also useful for rules like event("['!^@Timeofday==Day',...]"). If not 'once' was used it would be true every minute when the rule was run and not just the first time 'Timeofday' was set to 'Day'. Now '@Timeofday==Day' need to be false before it will return true again. There is also a {'truefor':<expression>, 'val':<seconds>} that returns true only if the expression has been true for a certain time (I haven't found a great use for this myself yet. Maybe if you want to send a notify every x minute if a door is open...) Anyway, beacuse rules are invoked at predefined intervals, some thinking is needed to get rules correct. Watch up with movement sensors reset times, if people turn on and off switches in shorther intervals than your rules are run etc. The 'last' property gives the number of seconds since the device changed value is very useful to get around this... Oh, there is also the 'cron' like time/date test to make more flexible time conditions: '!{<min> <hour> <day> <month> <weekday>}' and expands to {'interval':'<min> <hour> <day> <month> <weekday>'}. It uses the standard UNIX cron format also used and explanied in my previous scheduler. Ex. '!{0/15 9,13,17 * jun-aug sat-tue}' Is true every 15 minutes on the hour 9,13, and 17 during June to August at Saturday,Sunday,Mondat, and Tuesday... '!{0 0/2 * * sat,wed}' is true once every even hour on Saturdays and Wednesdays. Ok, there are many more features. There is a '!!' macro that turns on logging of a rule. That is convenient because logging can be turned on after some tests have returned true to not litter the logg to much. i.e. event("['![10:00]','!!',...]") only logg if it is 10... ('!!' macro expands to {'startdebug':true}) Logging can also be turned on per rule; event("['![10:00]',...]").debug(true) Debugging can also be turned on for all rules by setting the local lua variable 'debugAllRules' to true. There is also a 'debugLevel' that controls output and a 'debugProps' that if true debugs every call to fibaro:getValue and fibaro:getGlobal. Per default a statistics is shown in the log every night at 1:00, showing how many rules and triggers have been invoked. $variables can be functions. defvar('test',function() return 'Hello' end) will make '$test' return 'Hello'. '$Sunset','$Sunrise','$Now' is predefned variables using that approach. New primitive commands are quite easy to add to the "engine" with the defun function. Ex. I have the Sonos VD to play sound and a playSonosSound(file,volume,duration) lua function. To add a {'playfile':<filename>, 'volume':<expr>} for that ; -- {'playfile':file,'volume':val} defunLua('playfile','file', function(cmd, env) local file = env.eval(cmd.file) local volume = env.eval(cmd.volume) local duration = env.eval(cmd.duration) playSonosSound(file,volume,duration) return true end ) Functions can also be defined in json. Ex. defvar("myfun","{'fun':['x','y'], '&body':{'+':['$x','$y']}}") rule("[{'log':' 44 + 66 = %s', '&args':[{'call':'$myfun' ,'&args':[44,66]}]}]") If the scene is run remote in ZeroBrane using FibaroSceneAPI, live triggers does not work. However there is a hack. If you suspend the program and go to the Local Console window you can type lua expression for evaluation. Three commands are available to queue up events. qVal(id,prop,time,val) qGlob(name,time,val) qEvent(id,key,attr,time) qVal(331,'value,60,1) while queue a "331 value" event to be received in 60s and the value of 331 will be 1. See examples in function initOffline() in the src code. If I figure out how to do non-blocking read from the ZeroBrane console I could provide a more convenient command line function.... One anomaly with the FibaroSceneAPI is that it calls os.exit() if something goes wrong, i.e trying to access a non-existing deviceID on the HC2 and I can't catch that error and the scene terminates. The engine is pretty efficient, commands try to optimize themeselves when they are invoked the first time, and I'm trying to avoid stressing the GC too much by being restrictive on temporary datastructures created while running. I see very little CPU load with 40+ rules and 10+ triggers. The commands available now are; <time> -> "HH:MM" <time> -> "$Sunset" | "$Sunrise" | "$Now" (predefined user variables) <expr> -> {'time':<time1>} -- true if current time is time1 {'time':[<time1>,<time2>]} -- true if current time is between time1 and time2 (incl) {'time':[<time1>,<time2>,<time3>]} -- true if current time is time2 bracketed by time1 and time3 {'interval':'<cron format>'} -- see explanation earlier in the in doc {'>':[<expr1>,<expr2>]} -- true if expr1 > expr2 (>,<,==,>=, <=) {'+':[<expr1>,<expr2>]} -- returns expr1 + expr2 (+,-,*,/). '-' allows for {'-':<expr>} <prop> -> 'value', 'last', 'battery','power','lux','scene' <test> -> '>','<','==','>=','<=' <proptest> -> <prop><test> <id> -> any expression that returns an integer (or string representing an integer) that matches a device ID {'id':<id or array of ids> &<proptest1>:<expr1>, &<proptest2>:<expr2>,, ...} -- true if all tests applied to ids are true {<prop>:<id>} -- returns fibaro:get(<id>,<prop>) with 'lux' -> 'value' and 'last' being treated specially {<prop>:[<id1>,<id2>,...]} -- returns array [fibaro:get(<id1>,<prop1>),fibaro:get(<id2>,<prop2>),...] {'min':[<expr1>,<expr2>,...]} -- returns smallest of expressions {'max':[<expr1>,<expr2>,...]} -- returns largest of expressions {'mean':[<expr1>,<expr2>,...]} -- returns the average of expressions {'and':[<expr1>,<expr2>,...]} -- return true if all expressions are true {'or':[<expr1>,<expr2>,...]} -- return first value of first <expr> that is true {'not':<expr>} -- returns true if <expr> is false {'if':<expr1>, 'then':<expr2>, 'else':<expr3>} -- if-then-else test, else is optional {'on':<id or array of ids>} -- turns on all <ids> given as arguments, {'on?':<id or array of ids>} -- true if all <ids> have value>0 {'off':<id or array of ids>} -- turns off all <ids> given as arguments {'off?':<id or array of ids>} -- true if all <ids> have value<1 {'dim':<id or array of ids>,'&val':val} {'push':<mobile id>,'&msg':<string>,'&args':...} -- push message to phones, MobileID can be array of ids. Optional args are for formatting the message. See 'log' {'press':<id>,'&btn':<expr>} -- press button on VD {'start':<id or array of ids>} -- start scene(s) with ID (can be array) {'stop':<id or array of ids>}-- stops scene(s) with ID (can be array) {'glob':<expr>} -- fibaro:getGlobal(NAME) {'var':<expr>} -- getUserVariable(NAME) {'set':{'glob':<expr1>},'&val':<expr2>} -- fibaro:setGlobal(<expr1>,<expr2>), expr1 should evaluate to string {'set':{'var':<expr1>},'&val':<expr2>} -- setUserVariable(<expr1>,<expr2>), expr1 should evaluate to string {'enable':rule/table} -- enables the rule {'disable':rule/table} - disable the rule {'log':<expr>,'&args':...} -- log to the fibaro console, 'args' optional ex {'log':'Time global is ",'args':['@Time']} {'date':<expr1>,'&val':<expr2>} -- date form (e.g. os.date()) {'date':'%H:%M','val':'$Now'} -> i.e "10:00", useful for logging/messages {'once':<expr or array of expr>} -- returns false if EXPR hasn't changes, otherwise return EXPR {'truefor':<expr1>, '&val':<expr2>} -- returns true if EXPR has been true for SECONDS, otherwise false {'setTimer':<string>, '&val':<expr>} -- sets a timer with name that becomes true after <expr> seconds {'timer':<string>} -- returns true if the timer has expired {'clearTimer':<string>} -- cancel a timer that is running. {'label':<id>,'&val':<expr>} -- return the value of an VD label 'ui.<expr>.label' {'setLabel':<id>,'&val':<expr1>, '&expr':<expr2>} -- sets VD label 'ui.<expr1>.label'to <expr2> {'format':<string>, '&args':<array of expr>} -- makes a string.format {'fun':[parameters], '&body':<expr or array of expr>} -- defines a function, ex. {'fun':['x','y'], 'body':{'+':['$x','$y']}} {'call':<expr>, '&args':<array of expr>} -- makes a a call to a json defined fun {'decode':<string>} -- returns json.decode on the string {'encode':<expr>} -- returns json.encode on the expr {'devices':<expr>} -- calls fibaro:getDevicesId(expr). Note!, need to quote a constant json expr {'%':<expr>} -- quote.. returns expr without evaluating it {'fcall':<id or array of ids>, 'args':[<expr1>,<expr2>,......]} -- Makes a fibaro:call(<id>, <expr1>,<expr2>,...) Second release: , Supports CentralSceneEvent. '$_src' is set to fibaro:getSourceTrigger() which can be used in the trigger to decide keys etc. Ex. Keyfob with id 362. trigger("{'event':362}","[{'log':'Key %s %s', '&args':['$_src.event.data.keyId','$_src.event.data.keyAttribute']}]") To check a key sequence this works: defvar("key",{k1=0,k2=0}) trigger("{'event':362}","['!$_src.event.data.keyId==1','!$key.k1=$Now']") trigger("{'event':362}","['!$_src.event.data.keyId==2','!$Now<=$key.k1+1','!$key.k2=$Now']") trigger("{'event':362}","['!$_src.event.data.keyId==3','!$Now<=$key.k2+1',{'log':'Sequence 123'}]") Release 03/14: , Fixed subtle trigger bug Release 03/14: , Now supports functions. A small step towards templates... $variables are now auto created at first use if not previous defined with defvar(...). Release 03/16: JSched_0_95.lua, New functionality; init(<expr>), quoting of args, generic fibaro:call, etc Release 03/18: , JSched_0_96r3.lua,Bugfixes, better error handling, better offline support. "out-of-the-box" it runs the simulation offline. Release 04/03: JSched_0_98.lua, New syntax and better simulation support Macros: ...to be documented - for now see text above.
  23. Thought this easy LUA scene to turn off all lights using the new(ish) fibaro:getDevicesId() function might be helpful to others. -- get light id's local ids = fibaro:getDevicesId( { interfaces = { "light", }, properties = { dead = false, }, enabled = true, visible = true, -- optional } ); -- loop through light ids for i, id in ipairs(ids) do fibaro:debug("Turning off " .. fibaro:getName(id)); -- turn light off fibaro:call(id, "turnOff"); end
  24. Hi there, I just released a scene to overwrite heatpanel on public holidays. You need a global variable named holidayToday with the value 1 on public holidays, so the scene will set manual target temperature from sundays heatplan to all your rooms. overwrite you weekday heatplan with the one for sunday. No more manual mode required. Just have a look and translate if necessary: http://www.mkshb.de/heizplan-fuer-feiertage/ Here is todays scene version: --[[ %% properties %% globals holidayToday --]] --------------------------------------------------- --------- Verwendung ------------------------------ --[[ Anpassung des Heizplanes wenn heute ein Feiertag ist Die Heizpläne aller Räume werden manuell auf den Heizplan für Sonntags gesetzt. Trigger: Timer der alle x Minuten checkt ob ein Feiertag ist --]] --------------------------------------------------- --------- Schleifenschutz ------------------------- if (fibaro:countScenes()>1) then fibaro:debug('Kill the second scene!'); fibaro:abort(); end --------------------------------------------------- ------------- Config ------------------------------ gHolidayToday = 'holidayToday' gHeatplanOverwrite = 'heatplanOverwrite' advDebug = true version = 'v1.0' --------------------------------------------------- --------- Farbiges Debug -------------------------- function debug( color, message ) fibaro:debug(string.format('<%s style="color:%s;">%s<!--%s-->', "span", color, message, "span")); end --------------------------------------------------- ------------- HTTP GET ---------------------------- -- GET zum Auslesen des Heizplanel --------------------------------------------------- local function getMethod(requestUrl, successCallback, errorCallback) local http = net.HTTPClient() http:request(requestUrl, { options = { method = 'GET' }, success = successCallback, error = errorCallback }) end --------------------------------------------------- ------------- HTTP PUT ---------------------------- -- PUT zum Senden an das Heizplanel --------------------------------------------------- local function putMethod(requestUrl, data, successCallback, errorCallback) local http = net.HTTPClient() http:request(requestUrl, { options = { method = 'PUT', data = json.encode(data) }, success = successCallback, error = errorCallback }) end --------------------------------------------------- ------------- getHeatPlanIDs --------------------- -- HTTP Befehle zum Abrufen der Heizplan IDs --------------------------------------------------- function getHeatPlanIDs(state) url = 'http://127.0.0.1:11111/api/panels/heating' getMethod(url, function(resp) if resp.status == 200 then debug('green','Abrufen der Heizplan IDs erfolgreich (HTTP Status ' .. resp.status .. ')') panel = json.decode(resp.data) if state == true then for i = 1, #panel do gVarName = 'heatplan'..panel[i].id debug('yellow','Heizplan mit der ID '..panel[i].id..' gefunden') getHeatplan(panel[i].id, gVarName) end elseif state == false then for i = 1, #panel do gVarName = 'heatplan'..panel[i].id debug('yellow','Heizplan mit der ID '..panel[i].id..' gefunden') resetHeatplan(panel[i].id, gVarName) end end else debug('red','Verbindung konnte nicht hergestellt werden (HTTP Status ' .. resp.status .. ')') end end, function(err) debug('red','error ' .. err) end ) end --------------------------------------------------- ------------- getHeatplan ------------------- -- HTTP Befehle zum Auslesen des Heizplans --------------------------------------------------- function getHeatplan(roomID, gVarName) local url = 'http://127.0.0.1:11111/api/panels/heating/' .. roomID getMethod(url, function(resp) if resp.status == 200 then if fibaro:getGlobal(gVarName) == nil then createGlobalVar(gVarName, resp.data) debug('yellow','Globale Variable '..gVarName..' erstellt') end heatplan = json.decode(resp.data) roomName = heatplan.name fibaro:setGlobal(gVarName, resp.data) fibaro:setGlobal(gHeatplanOverwrite, '1') debug('green','Heizplan "'..roomName..'" gespeichert und gesperrt') modifyHeatplan(heatplan, weekday) else debug('red','Verbindung konnte nicht hergestellt werden (HTTP Status ' .. resp.status .. ')') end end, function(err) debug('red','error ' .. err) end ) end --------------------------------------------------- ------------- modifyHeatplan ------------------- -- Bearbeite Heizplan --------------------------------------------------- function modifyHeatplan(heatplan, weekday) if weekday == 'monday' then heatplan.properties.monday = heatplan.properties.sunday heatplan.properties.tuesday = heatplan.properties.sunday elseif weekday == 'tuesday' then heatplan.properties.tuesday = heatplan.properties.sunday heatplan.properties.wednesday = heatplan.properties.sunday elseif weekday == 'wednesday' then heatplan.properties.wednesday = heatplan.properties.sunday heatplan.properties.thursday = heatplan.properties.sunday elseif weekday == 'thursday' then heatplan.properties.thursday = heatplan.properties.sunday heatplan.properties.friday = heatplan.properties.sunday elseif weekday == 'friday' then heatplan.properties.friday = heatplan.properties.sunday heatplan.properties.saturday = heatplan.properties.sunday elseif weekday == 'saturday' then heatplan.properties.saturday = heatplan.properties.sunday heatplan.properties.sunday = heatplan.properties.sunday elseif weekday == 'sunday' then heatplan.properties.sunday = heatplan.properties.sunday heatplan.properties.monday = heatplan.properties.sunday end heatplanJSON = json.encode(heatplan) local http = net.HTTPClient() http:request("http://127.0.0.1:11111/api/panels/heating/"..heatplan.id, { options = { method = 'PUT', headers = {}, data = heatplanJSON, timeout = 10000 }, success = function(response) local result = response.data; if response.status == 200 or response.status == 201 then debug('green','Status: ' ..response.status.. ' - Heizplan überschrieben') else debug('red','Error: ' ..response.status.. ' - Zugriff verweigert') end end, error = function(err) debug('red','[ERROR] ' .. err) end }) end --------------------------------------------------- ------------- resetHeatplan ------------------- -- Setze Heizpläne zurück --------------------------------------------------- function resetHeatplan(heatplanID, gVarName) heatplanJSON = fibaro:getGlobal(gVarName) local http = net.HTTPClient() http:request("http://127.0.0.1:11111/api/panels/heating/"..heatplanID, { options = { method = 'PUT', headers = {}, data = heatplanJSON, timeout = 10000 }, success = function(response) local result = response.data; if response.status == 200 or response.status == 201 then debug('green','Status: ' ..response.status.. ' - Heizplan zurückgesetzt') else debug('red','Error: ' ..response.status.. ' - Zugriff verweigert') end end, error = function(err) debug('red','[ERROR] ' .. err) end }) end --------------------------------------------------- ------------- Handle gVar ---------------------------- -- globale Variable handeln --------------------------------------------------- function createGlobalVar(var,value) local http = net.HTTPClient() http:request("http://127.0.0.1:11111/api/globalVariables", { options = { method = 'POST', headers = {}, data = '{"name":"'..var..'","value":"'..value..'"}', timeout = 10000 }, success = function(response) local result = response.data; if response.status == 200 or response.status == 201 then debug('green','Status: ' ..response.status.. ' - Variable wurde angelegt') else debug('red','Error: ' ..response.status.. ' - Zugriff verweigert') end end, error = function(err) debug('red','[ERROR] ' .. err) end }) end -- Start der Verarbeitung -- Prüfen ob Save Variable gHeatplanOverwrite vorhanden. Wenn nicht, dann erstellen. if fibaro:getGlobal(gHeatplanOverwrite) == nil then createGlobalVar(gHeatplanOverwrite, '0') end --fibaro:setGlobal(gHeatplanOverwrite, '0') weekday = string.lower(os.date('%A')) debug("green","--------------------START--------------------------------") debug("green","------------ Heizpläne an Feiertagen ------------") debug("green","------------------------------------------------------------") debug("green","------------ Prüfe Feiertagsvariable") if fibaro:getGlobal(gHolidayToday) == '1' then debug('yellow','Heute ist ein Feiertag.') if fibaro:getGlobal(gHeatplanOverwrite) ~= '1' then debug('yellow','Es wird der Heizplan für Sonntag übernommen.') getHeatPlanIDs(true) else debug('red','Heizpläne bereits überschrieben.') end else if fibaro:getGlobal(gHeatplanOverwrite) == '1' then debug('green','Heute ist kein Feiertag mehr, setze Heizpläne zurück') getHeatPlanIDs(false) fibaro:setGlobal(gHeatplanOverwrite, '0') else debug('green','Heute ist kein Feiertag.') end end Have fun and some nice days with your families. Regards Neospin aka Bastian
  25. Multiroom Heating Controller My project was to write a multiroom heating controller to give indipendant control over each room using as much as the built in functionality of Home Center 2 as possible. Starting point: Create multiple rooms in the heating panel in accordance with the Advanced User Guide section 5.9.3 I did have some code to enumerate from these panels and get the following from the JSON files http://yourHC2IPAddress/api/panels/heating & http://yourHC2IPAddress/api/rooms Room Name, Room "Default Thermostat" & Default Temperature Sensor As I failed to add them to my array roomsArray I abandoned this for the time being. (Any developers want to help here??? You add your rooms to the roomsArray, set the HeatON and HeatOff as you need them these will stop overshoot of Temperature. - Any developers want to turn this in to a heating PID? I have been running this now for a couple of months without problem, and even moved it to other HC2 controllers. Make a LUA Scene, drope the code in, change the Variables and away you go. My setup and all I have tested with: HC2 v 4.1x Danfoss LC-13 TRVs these control the radiators and also act as a Thermostat for any room that does not have a external Thermostat Fibaro or AEON Multisensor for Temperature Sensor Secure SRT321 Wall thermostat & Secure HRT boiler Receiver - This was so i could put in manual mode if anything went wrong Happy to have suggeestions and additions! Enjoy! Brent --[[ %% autostart %% properties %% globals --]] -- REFERENCE -- forum.fibaro.com, lua.org, domotique-fibaro.fr, www.zwaveforum.net -- 0.0.1 2/11/16 iniital version -- 0.0.2 3/11/16 added get setpoint fucntion -- 0.0.3 4/11/16 Get Setpoints from Heating Panel -- Scrapped for -- 0.0. 11/11/16 Get default sensors from roms panel version = '1.0.0' -- 13/11/16 Stable version -- local arrays local roomsArray={} local heatOn = 0.7 -- temp has to drop this value below setpoint before boiler is on again -- adjust these two levels to reduce the sawtooth effect. local heatOff = 0.5 local smoothFactor = 3 local boilerControllerID=97 local programStart = os.time() local boilerOnTime = 0 local boilerOffTime = 0 local boilerOnTotal = 0 -- roomsArray[Room Name]={SetPointID, ThermostatID} -- These are temporary until Panels and Rooms Functions return Arrays roomsArray[1]={'Lounge',99,12} roomsArray[2]={'Master Bedroom',100,13} roomsArray[3]={'Kitchen',101,14} roomsArray[4]={'Bathroom',102,15} -------------------- USER SETTINGS ----------------------- --This will be redundant with version 0.0.4 debug = true -- set debug to true or false enumerateRooms = true -- Set this to true and within the debug window on the scene advance tab you will see room names and IDs enumerateSensors = true -- Set this to true to see within the Debug Window on the scene advance tab you will see Sensors for the room names and IDs enumerateErrors = true ----------------------------------------------------------- ------------- DO NOT CHANGE LINES BELOW ------------------- startSource = fibaro:getSourceTrigger(); -- Not using this at this time but will do BJB -- Give debug a fancy color Debug = function ( color, message ) fibaro:debug(string.format('<%s style="color:%s;">%s</%s>', "span", color, message, "span")); end Debug( "orange", "Read Heating Panel scene - LUA Scripting by Brent Brown 2016" ); Debug( "orange", "Version: "..version); -- Passed RoomID, ThermostatID, TemporatureSensorID -- Returns via adding to roomsArray TermostatSetpoint, currentTemperature, errorTemperature getTempError = function(room, tempID, thermID) local temperatureError = -999 if type(tonumber(fibaro:getValue(thermID, "targetLevel"))) ~= 'number' then if enumerateErrors == true then Debug("Green", "The device Thermostat in room " .. roomsArray[room][1] .. " has a NIL value!") Debug("Green", fibaro:getValue(thermID, "targetLevel")) temperatureError=0 end elseif type(tonumber(fibaro:getValue(tempID, "value"))) ~= 'number' then if enumerateErrors == true then Debug("Red", "The device temperature sensor in room " .. roomsArray[room][1] .. " has a NIL value!") Debug("Red", fibaro:getValue(tempID, "value")) temperatureError=0 end else roomsArray[room][5]=tonumber(fibaro:getValue(tempID, "value")) roomsArray[room][4]=tonumber(fibaro:getValue(thermID, "targetLevel")) roomsArray[room][6]=tonumber(fibaro:getValue(thermID, "targetLevel")) - tonumber(fibaro:getValue(tempID, "value")) end return temperatureError end meanTempFunc = function() local averageTempError, count = 0, 0 for k,v in pairs(roomsArray) do if debug == ture then Debug("White",roomsArray[k][6]) end if type(roomsArray[k][6]) ~= 'number' then if debug == ture then Debug("Red",roomsArray[k][1]..", TempError is not a number [Nil]") end elseif roomsArray[k][6] <= 0 then if debug == true then Debug("Red", roomsArray[k][1]..", is "..roomsArray[k][6]*-1 .."° above SetPoint") end else if debug == true then Debug("Blue", roomsArray[k][1]..", is: "..roomsArray[k][6]*-1 .."° below SetPoint") end averageTempError = averageTempError + roomsArray[k][6] count = count + 1 end end if count == 0 then averageTempError = 0 Debug("Blue","Average temperature across "..count.." room(s), is:"..averageTempError.."°") else averageTempError=averageTempError/count Debug("White","Average temperature across "..count.." room(s), is:"..averageTempError.."°") end return averageTempError end debugRoomFunc = function(room) if type(roomsArray[room][4]) == 'number' then Debug("White", roomsArray[room][1].." SetPoint Temperature is: "..roomsArray[room][4]) end if type(roomsArray[room][5]) == 'number' then Debug("White", roomsArray[room][1].." Sensor is showing the Temperature is: "..roomsArray[room][5]) end if type(roomsArray[room][6]) == 'number' then Debug("White", roomsArray[room][1].." Error Temperature is: "..roomsArray[room][6]) end end -- Main Process while true do local boilerOnTime for k, v in pairs(roomsArray) do --Debug("White", k..'.'..roomsArray[k][2]..'.'..roomsArray[k][3]) -- From each room get the Setpoint - Temperature to give ErrorTemperature getTempError(k,roomsArray[k][2],roomsArray[k][3]) end -- Get Each positive error temperature from roomArray[roomID][6] == ErrorTemp local meanTempError=meanTempFunc() Debug("Yellow",meanTempError) if meanTempError > 0 and meanTempError > heatOn then if tonumber(fibaro:getValue(boilerControllerID,"mode"))~=1 then fibaro:call(boilerControllerID, "setMode",1) boilerOnTime=os.time() Debug("Yellow", "Boiler on at = "..os.date("%X")) end end if meanTempError < heatOff then if tonumber(fibaro:getValue(boilerControllerID,"mode"))~=0 then fibaro:call(boilerControllerID,"setMode",0) boilerOnTotal=os.difftime(os.time(), boilerOnTime) Debug("White", "The boiler has been on for ".. boilerOnTotal.. " Seconds") fibaro:sleep(120000) -- Wait 2 mins whilst the latent heat tin the system keeps warming the room Debug("Yellow", "Boiler off at = "..os.date("%X")) end end --[[local whichRooms = "All" -- Options all or room 1,2,3,4,5, etc if whichRooms == "All" then for k, v in pairs(roomsArray) do debugRoomFunc(k) end -- Remove the comment "--" to show each of the room settings else debugRoomFunc(whichRooms) end --]] fibaro:sleep(30000) end Brent
×
×
  • Create New...