Aller au contenu

Rechercher dans la communauté

Affichage des résultats pour les étiquettes 'tuto hc2'.



Plus d’options de recherche

  • Rechercher par étiquettes

    Saisir les étiquettes en les séparant par une virgule.
  • Rechercher par auteur

Type du contenu


Forums

  • Bienvenue
    • Annonces et suggestions
    • Nouveau ? Présentez-vous
    • Le bistrot
    • Mon installation domotique
    • Autres Solutions Domotiques
  • La HC2 et ses périphériques
    • La Home Center pour les nuls
    • Home Center 2 & Lite
    • Modules Fibaro
    • Modules Z-wave
    • Périphériques et matériels autres
    • Plugins
    • Alarme & Vidéo-surveillance
    • Multimédia
    • Chauffage et Energie
    • Actionneurs & Ouvrants (Portail, volets...)
    • Eclairage
    • Applications Smartphones et Tablettes
    • English Section
  • Les objets connectés
    • Les Assistants Vocaux
  • Fibaro's Awards
    • Membre du mois
    • Jeux concours & Cadeaux
  • Les bonnes affaires
    • Sites internet
    • Petites annonces

Rechercher les résultats dans…

Rechercher les résultats qui…


Date de création

  • Début

    Fin


Dernière mise à jour

  • Début

    Fin


Filtrer par nombre de…

Inscription

  • Début

    Fin


Groupe


Jabber


Skype


Ville :


Intéret :


Version

132 résultats trouvés

  1. Ce module permet de piloter l'arrêt, la petite et la grande vitesse à l'aide d'un FGS-221. La VMC n'est pas prévue pour être à l'arrêt initialement mais je trouve ridicule de la faire tourner les jours rouges (je suis en Tempo) qui sont généralement les plus froids. Une conso électrique pour en plus mettre de la chaleur dehors, plus jamais même si les radiateurs à chaleur douce sont en appoint d'un insert. La salle de bain à l'étage est en pignon et assez éloignée de la trémie de l'escalier donc pas réellement chauffée par l'insert. . Voici le schéma sur lequel je suis partit. Ayant un doute sur la possibilité de ma VMC à lui raccorder la grande vitesse en même temps que la petite, j'ai préféré ajouter un relais inverseur pour suivre le même câblage que le va-et-vient d'origine. L'astuce est de faire le pont entre la phase et O1 (marche-arrêt) puis d'alimenter le contact inverseur du relais en In et enfin sortir de O2 pour alimenter la bobine du relais (PV-GV). J'ai choisi des poussoirs à voyant Mosaïc pour les commandes et pour l'état un voyant vert pour la marche en petite vitesse et un voyant rouge sur le second poussoir pour la grande vitesse. Il me manquait des fils entre la VMC et une boîte à l'étage (au dessus du plan de travail). Je vous précise cela car ça ne voulait pas passer et j'ai été obligé de débrancher les fils existants dans la gaîne (circuit PC + circuit 20A + alim. d'un éclairage + 3 fils VMC), d'y accrocher une aiguille et ressortir les 7 mètres pour y ajouter mon neutre + d'autres en réserve pour ensuite les repasser tous ensemble (c'était chaud mais pas impossible). Pour les commandes des boutons, rien de compliqué La main loop pour le retour des 3 états. Un grand MERCI à Steven qui, une fois de plus à répondu présent pour me dépatouiller de Lua. --[[ %% properties %% globals --]] local id_vmc_lent = 236 local id_vmc_rapide = 238 local id_module_virtuel = fibaro:getSelfId() local lentAllumer = tonumber(fibaro:getValue(id_vmc_lent, "value")) == 1 local rapideAllumer = tonumber(fibaro:getValue(id_vmc_rapide, "value")) == 1 local icon = fibaro:getValue(id_module_virtuel, "currentIcon") if (lentAllumer and rapideAllumer) then -- icone rapide icon = 1097 elseif (lentAllumer) then -- icone lent icon = 1096 else -- icone éteint icon = 1091 end fibaro:call(235, "setProperty", "currentIcon", icon) Et enfin, les icônes au cas où vous ne les auriez pas déjà trouver dans le topic de Steh (Banque Icônes Hc2 & Hcl). Bien sûr, je n'ai pas fait ce module juste pour pouvoir m'amuser avec la VMC de la tablette mais je compte bien la faire taire complètement les jours rouges et peut-être aussi lui faire forcer la grande vitesse quand le taux d'humidité dans la gaîne de la salle de bain sera trop élevé mais encore faudrait-il trouver une sonde adéquate.
  2. Bonjour, Voilà , le code est enfin correct, je le partage donc. Je n'ai pas beaucoup de temps ce soir, mais voici 2-3 points: - Ce VD crée automagiquement 3 Variables globales (si demandé dans les options) - Ce VD est multilingue - Ce VD fait des push de la météo à deux moments de la journée - CE VD s'adapte aux mobiles et à l'interface web - Ce VD télécharge automagiquement les icônes - Ce VD a besoin d'une clef APi de Wunderground, - La partie mobile du VD n'est pas encore complètement terminée. Merci à Jompa68 de forum.fibaro.com pour le code de base Pour l'installer: - Téléchargez le vfib attaché et importez le dans la HC2 - Changer l'icône du slider avec l'icône attachée: - Utilisez le dernier code disponible sur github: https://github.com/sjauquet/YAMSWU Qui ajoute la création de VG qui contiendront la météo prononçable par une synthèse vocale comme S.A.R.A.H.: http://www.domotique-fibaro.fr/index.php/topic/6446-yams-wu-yet-another-meteo-station-wunderground-version/page-4#entry132933 et placez-le dans le main loop du VFIB (V3.9) attaché à ce message - Changez l'api key. Pour cela, créez un compte wunderground et allez la récupérer ici: http://www.wunderground.com/weather/api/ WU.APIkey = "xxxxxxxxxxxxxxx" - Ensuite définissez les variables suivantes: WU.PWS = "IGVLEBOR5" -- The PWS location to get data from (Personal Weather Station) WU.LOCID = "SWXX0076" -- The location ID to get data from (City location) WU.station = "PWS" -- Choose your prefered method to retrieve from: PWS or LOCID Personnellement je préfère utiliser les infos d'une pws près de chez moi. Pour trouver ces variables: @bono2007 écrivait: Pour trouver, j'ai eu la station PWS en cliquant dans "Search locations" sur Wunderground, on te propose "search nearest station", et il a proposé une station météo proche. Sinon en entrant ta ville, tu peux cliquer sur "change Station" et tu verras une carte avec d'autres stations météo. Exemple : j'ai entré "Boussois" et j'ai comme station météo "Cit du Grand Bois, Récquignies ( IRECQUIG2) J'ai modifié WU.PWS = "IRECQUIG2" Et tout devrait fonctionner :-) Virtual device avec code V3.7 (ancien à remplacer !!! ) YAMS_WU.vfib Virtual device avec code V3.9 YAMS_WU V3.9.vfib Voici les dernières captures d'écran pour avoir une idée: à gauche en mode Browser Web, à droite en mode Mobile (les icônes ne sont pas téléchargeables) Attention, ancien code ci-dessous ! ------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------- -- WU WeatherData - Fetch weather data from wunderground.com. Multilanguage support! -- Original Code by Jonny Larsson 2015 http://forum.fibaro.com/index.php?/topic/19810-wu-weatherdata-version-202-2015-10-25/ -- forked by Sébastien Jauquet 11/2015 -- Inspired by GEA(steven), stevenvd, Krikroff and many other users. -- Source - forum.fibaro.com, domotique-fibaro.fr and worldwideweb -- -- Version 3.7 -- -- 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-11-13 - V3.0 - Fork Code by Sebastien Jauquet (3 days forecast, rain in mm) -- 2015-11-14 - V3.1 - Compatibilty with GEA, French translation -- 2015-11-14 - V3.2 - Catch rain errors (-999mm null empty etc.) -- 2015-11-14 - V3.3 - Catch json decode error (was stopping main loop) with pcall (can be extended to other jdon datas if needed) -- 2015-11-16 - V3.4 - Generate HTML and non HTML version (for compatibility with mobiles) -- 2015-11-18 - V3.5 - Fixed bug not updating Meteo_Day becaus WU.now was only updated at first launch -- 2015-11-18 - V3.6 - Merged some changes from jompa new version -- 2015-11-18 - Added autmatic creation of Global Variables if not existing -- 2015-11-19 - V3.7 - Modify schedule management and CleanUp code -- Look for nearest station here: http://www.wunderground.com ------------------------------------------------------------------------------------------- -- MAIN CODE -- ------------------------------------------------------------------------------------------- WU = {} -- WU settings WU.APIkey = "xxxxxxxxxxxxxxx" -- Put your WU api key here 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 -- Other settings WU.translation = {true} WU.language = "FR"; -- EN, FR, SW, PL (default is en) WU.smartphoneID = 1347 -- your smartphone ID WU.sendPush = true -- send forecast as push message WU.push_fcst1 = "07:00" -- time when forecast for today will be pushed to smartphone WU.push_fcst2 = "18:15" -- time when forecast for tonight will be pushed to smartphone WU.GEA = true -- subst % with %% when storing in the VG's (because gea bug with % in push messages) WU.CreateVG = true -- will atomaticaly create global variables at first run if = true updateEvery = 30 -- get data every xx minutes WU.startTime = os.time() WU.scheduler = os.time()+60*updateEvery WU.currentDate = os.date("*t"); WU.now = os.date("%H:%M"); DoNotRecheckBefore = os.time() WU.selfId = fibaro:getSelfId() WU.version = "3.7" WU.translation["EN"] = { Push_forecast = "Push forecast", Exiting_loop_slider = "Exiting loop earlier (Slider Changed)", Exiting_loop_push = "Exiting loop earlier (For push)", Last_updated = "Last updated", 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", NO_STATIONID_FOUND = "No stationID found", NO_DATA_FOUND = "No data found" } WU.translation["FR"] = { Push_forecast = "Push des prévisions", Exiting_loop_slider = "Sortie de boucle (Slider Changé)", Exiting_loop_push = "Sortie de boucle (Pour Push)", Last_updated = "Mise à jour", Temperature = "Actuellement", Humidity = "Hum", Pressure = "Pression", Wind = "Vent", Rain = "Pluie", Forecast = "Prévisions pour ce", Station = "Station", Fetched = "Données Reçues", Data_processed = "Données mises à jour", Update_interval = "Prochaine Mise à jour prévue dans (min)", No_data_fetched = "Pas de données reçues !!", NO_STATIONID_FOUND = "StationID non trouvée !!", NO_DATA_FOUND = "Pas de données disponibles !!" } WU.translation["SW"] = { Push_forecast = "Push forecast", Exiting_loop_slider = "Exiting loop earlier (Slider Changed)", Exiting_loop_push = "Exiting loop earlier (For push)", Last_updated = "Last updated", Temperature = "Temperatur", Humidity = "Fuktighet", Pressure = "Barometer", Wind = "Vind", Rain = "Regn", Forecast = "Prognos", Station = "Station", Fetched = "Hà¤mtat", Data_processed = "All data processat", 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"] = { Push_forecast = "Push prognoza", Exiting_loop_slider = "Exiting loop earlier (Slider Changed)", Exiting_loop_push = "Exiting loop earlier (For push)", Last_updated = "Last updated", Temperature = "Temperatura", Humidity = "Wilgotnosc", Pressure = "Pressure", Wind = "Wiatr", Rain = "Rain", Forecast = "Forecast", Station = "Station", Fetched = "Fetched", Data_processed = "Data processed", No_data_fetched = "No data fetched", Update_interval = "Next update will be in (min)", NO_STATIONID_FOUND = "No stationID found", NO_DATA_FOUND = "No data found" } WU.translation["NL"] = { Push_forecast = "Push verwachting", Exiting_loop_slider = "Exiting loop earlier (Slider Changed)", Exiting_loop_push = "Exiting loop earlier (For push)", Last_updated = "Last updated", Temperature = "Temperatuur", Humidity = "Vochtigheid", Pressure = "Druk", Wind = "Wind", Rain = "Regen", Forecast = "Verwachting", Station = "Weerstation", Fetched = "Ontvangen", Data_processed = "Gegevens verwerkt", 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"] = { Push_forecast = "Push vorhersage", Exiting_loop_slider = "Exiting loop earlier (Slider Changed)", Exiting_loop_push = "Exiting loop earlier (For push)", Last_updated = "Last updated", Temperature = "Temperatur", Humidity = "Luftfeuchtigkeit", Pressure = "Luftdruck", Wind = "Wind", Rain = "Regen", Forecast = "Vorhersage", Station = "Station", Fetched = "Abgerufen", Data_processed = "Daten verarbeitet", 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" } Debug = function ( color, message ) fibaro:debug(string.format('<%s style="color:%s;">%s</%s>', "span", color, message, "span")); end WU.createGlobalIfNotExists = function (varName, defaultValue) if (fibaro:getGlobal(varName) == "") then Debug("red", "Global Var: "..varName.." HAS BEEN CREATED") newVar = {} newVar.name = varName HC2 = Net.FHttp("127.0.0.1", 11111) HC2:POST("/api/globalVariables", json.encode(newVar)) end end WU.substPercent = function(doublePercentSymbol) if WU.GEA then doublePercentSymbol = string.gsub(doublePercentSymbol, "%%.", "%%%%") end return doublePercentSymbol end WU.cleanJson = function(jsontocheck,returnIfTrue) if jsontocheck == "-999.00" or jsontocheck == "--" or jsontocheck == json.null then jsontocheck = returnIfTrue end local ok = pcall(function() testConcatenate = "Test Concatenate: " .. jsontocheck -- test for non concatenate value end ) if (not ok) then decode_error = true Debug( "red", "decode raised an error") fibaro:call(WU.smartphoneID , "sendPush", "decode error in WU Meteo") end return jsontocheck end WU.HtmlColor = function(StringToColor,color) if MobileDisplay == false then StringToColor= "<font color=\""..color.."\"> "..StringToColor.."</font>" end return StringToColor end WU.IconOrText = function(icon,txt) if MobileDisplay == false then IconOrText = "<img src="..icon.."\>" else IconOrText = txt end return IconOrText end WU.getSlider = function() ValeurSliderfunct = fibaro:getValue(WU.selfId , "ui.WebOrMobile.value") return tonumber(ValeurSliderfunct) end WU.setSlider = function(position) fibaro:call(WU.selfId , "setProperty", "ui.WebOrMobile.value", position) return WU.getSlider() end WU.checkMobileOrWeb = function() ValeurSliderSleep = WU.getSlider() -- check slider value at first run if ValeurSliderSleep <= 50 then if ValeurSliderSleep == 1 then MobileDisplay = false else MobileDisplay = false WU.runDirect = 1 sleepAndcheckslider = 20*updateEvery -- exit wait loop Debug("orange", WU.translation[WU.language]["Exiting_loop_slider"]); end WU.setSlider(1) -- désactive le run immediat lors du prochain test end if ValeurSliderSleep >= 50 then if ValeurSliderSleep == 98 then else MobileDisplay = true WU.runDirect = 1 sleepAndcheckslider = 20*updateEvery -- exit wait loop Debug("orange", WU.translation[WU.language]["Exiting_loop_slider"]); end WU.setSlider(98) -- désactive le run immediat lors du prochain test end return WU.getSlider() end WU.fetchWU = function() decode_error = false WU.checkMobileOrWeb() local WGROUND = Net.FHttp("api.wunderground.com",80); local response ,status, err = WGROUND:GET("/api/"..WU.APIkey.."/conditions/forecast/lang:"..WU.language.."/q/"..WU.station..":"..locationID..".json"); if (tonumber(status) == 200 and tonumber(err)==0) then Debug( "cyan", WU.translation[WU.language]["Fetched"]) if (response ~= nil) then WU.now = os.date("%H:%M") jsonTable = json.decode(response); if jsonTable.response.error ~= nil then Debug( "red", WU.translation[WU.language]["NO_DATA_FOUND"]) fibaro:sleep(15*1000) return end stationID = jsonTable.current_observation.station_id; 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 = WU.cleanJson(jsonTable.current_observation.precip_today_metric,"0") weathericon = jsonTable.current_observation.icon_url fcstday1 = jsonTable.forecast.txt_forecast.forecastday[1].title -- Day meteo fcst1 = jsonTable.forecast.txt_forecast.forecastday[1].fcttext_metric fcst1icon = jsonTable.forecast.txt_forecast.forecastday[1].icon_url fcst1SmallTxt = jsonTable.forecast.simpleforecast.forecastday[1].conditions fcst1Tmax = jsonTable.forecast.simpleforecast.forecastday[1].high.celsius fcst1Tmin = jsonTable.forecast.simpleforecast.forecastday[1].low.celsius fcst1avewind =jsonTable.forecast.simpleforecast.forecastday[1].avewind.kph fcst1avewinddir =jsonTable.forecast.simpleforecast.forecastday[1].avewind.dir fcst1mm = WU.cleanJson(jsonTable.forecast.simpleforecast.forecastday[1].qpf_day.mm,"0") fcstday2 = jsonTable.forecast.txt_forecast.forecastday[2].title -- Evening Meteo fcst2 = jsonTable.forecast.txt_forecast.forecastday[2].fcttext_metric fcst2icon = jsonTable.forecast.txt_forecast.forecastday[2].icon_url fcst2SmallTxt = jsonTable.forecast.simpleforecast.forecastday[2].conditions fcst2Tmax = jsonTable.forecast.simpleforecast.forecastday[2].high.celsius fcst2Tmin = jsonTable.forecast.simpleforecast.forecastday[2].low.celsius fcst2avewind =jsonTable.forecast.simpleforecast.forecastday[2].avewind.kph fcst2avewinddir =jsonTable.forecast.simpleforecast.forecastday[2].avewind.dir fcst2mm = WU.cleanJson(jsonTable.forecast.simpleforecast.forecastday[1].qpf_night.mm,"0") fcstday3 = jsonTable.forecast.txt_forecast.forecastday[3].title -- Tomorrow fcst3 = jsonTable.forecast.txt_forecast.forecastday[3].fcttext_metric fcst3icon = jsonTable.forecast.txt_forecast.forecastday[1].icon_url fcst3SmallTxt = jsonTable.forecast.simpleforecast.forecastday[1].conditions fcst3Tmax = jsonTable.forecast.simpleforecast.forecastday[1].high.celsius fcst3Tmin = jsonTable.forecast.simpleforecast.forecastday[1].low.celsius fcst3avewind =jsonTable.forecast.simpleforecast.forecastday[1].avewind.kph fcst3avewinddir =jsonTable.forecast.simpleforecast.forecastday[1].avewind.dir fcst3mm = WU.cleanJson(jsonTable.forecast.simpleforecast.forecastday[2].qpf_allday.mm,"0") fcstday5 = jsonTable.forecast.txt_forecast.forecastday[5].title -- In 2 days fcst5 = jsonTable.forecast.txt_forecast.forecastday[5].fcttext_metric fcst5icon = jsonTable.forecast.txt_forecast.forecastday[1].icon_url fcst5SmallTxt = jsonTable.forecast.simpleforecast.forecastday[1].conditions fcst5Tmax = jsonTable.forecast.simpleforecast.forecastday[1].high.celsius fcst5Tmin = jsonTable.forecast.simpleforecast.forecastday[1].low.celsius fcst5avewind =jsonTable.forecast.simpleforecast.forecastday[1].avewind.kph fcst5avewinddir =jsonTable.forecast.simpleforecast.forecastday[1].avewind.dir fcst5mm = WU.cleanJson(jsonTable.forecast.simpleforecast.forecastday[3].qpf_allday.mm,"0") if (stationID ~= nil) and decode_error == false then fibaro:call(WU.selfId , "setProperty", "ui.lblStation.value", locationID); if temperature < 5 then cTemperature = WU.HtmlColor(temperature,"blue") elseif temperature > 18 then cTemperature = WU.HtmlColor(temperature,"red") else cTemperature = WU.HtmlColor(temperature,"yellow") end fibaro:call(WU.selfId , "setProperty", "ui.lblTempHum.value", WU.translation[WU.language]["Temperature"]..": "..cTemperature.." °C - "..WU.translation[WU.language]["Humidity"]..": "..humidity); fibaro:call(WU.selfId , "setProperty", "ui.lblWindRain.value", WU.translation[WU.language]["Wind"]..": "..wind.." km/h - "..WU.translation[WU.language]["Rain"]..": "..rain.." mm"); if (WU.now >= "00:00" and WU.now <= "15:59") then -- donne meteo du jour entre 00:00 (ou 3h) et 15:59. permet de garder la météo du soir jusqu'a 3h du matin, sinon change à minuit fibaro:call(WU.selfId , "setProperty", "ui.lblFcst.value", WU.translation[WU.language]["Forecast"].." "..WU.HtmlColor(fcstday1,"yellow")..": "..WU.HtmlColor(fcst1.." ("..fcst1mm.." mm)","green")); fibaro:setGlobal("Meteo_Day", WU.substPercent(WU.translation[WU.language]["Forecast"].." "..fcstday1..": ".." "..fcst1.." ("..fcst1mm.." mm)") ); fibaro:call(WU.selfId , "setProperty", "ui.lblIcon.value",WU.IconOrText(fcst1icon,fcst1SmallTxt)); elseif (WU.now >= "16:00" and WU.now <= "23:59") then -- donne meteo soirée entre 16:00 et 23:59 fibaro:call(WU.selfId , "setProperty", "ui.lblFcst.value", WU.translation[WU.language]["Forecast"].." "..WU.HtmlColor(fcstday2,"yellow")..": "..WU.HtmlColor(fcst2.." ("..fcst2mm.." mm)","green")); fibaro:setGlobal("Meteo_Day", WU.substPercent(WU.translation[WU.language]["Forecast"].." "..fcstday2..": ".." "..fcst2.." ("..fcst2mm.." mm)") ); fibaro:call(WU.selfId , "setProperty", "ui.lblIcon.value",WU.IconOrText(fcst2icon,fcst2SmallTxt)); end -- Meteo of Tomorrow fibaro:call(WU.selfId , "setProperty", "ui.lblFcstTomorrow.value", WU.translation[WU.language]["Forecast"].." "..WU.HtmlColor(fcstday3,"yellow")..": "..WU.HtmlColor(fcst3.." ("..fcst3mm.." mm)","green")); fibaro:setGlobal("Meteo_Tomorrow", WU.substPercent(WU.translation[WU.language]["Forecast"].." "..fcstday3..": ".." "..fcst3.." ("..fcst3mm.." mm)") ); fibaro:call(WU.selfId , "setProperty", "ui.lblIconTomorrow.value",WU.IconOrText(fcst3icon,fcst3SmallTxt)); -- Meteo in 2 Days fibaro:call(WU.selfId , "setProperty", "ui.lblFcst2Days.value", WU.translation[WU.language]["Forecast"].." "..WU.HtmlColor(fcstday5,"yellow")..": "..WU.HtmlColor(fcst5.." ("..fcst5mm.." mm)","green")); fibaro:setGlobal("Meteo_In_2_Days", WU.substPercent(WU.translation[WU.language]["Forecast"].." "..fcstday5..": ".." "..fcst5.." ("..fcst5mm.." mm)") ); fibaro:call(WU.selfId , "setProperty", "ui.lblIcon2Days.value",WU.IconOrText(fcst5icon,fcst5SmallTxt)); if WU.sendPush then if (os.date("%H:%M") == WU.push_fcst1) then -- fibaro:call(WU.smartphoneID , "sendPush", fcstday1.." - "..fcst1) -- envoie meteo du matin elseif (os.date("%H:%M") == WU.push_fcst2) then fibaro:call(WU.smartphoneID , "sendPush", fcstday2.." - "..fcst2) -- envoie meteo du soir 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", WU.translation[WU.language]["Last_updated"]..": "..os.date("%c")); Debug( "cyan", WU.translation[WU.language]["Data_processed"]) Debug( "white", WU.translation[WU.language]["Update_interval"].." "..updateEvery) else Debug( "red", WU.translation[WU.language]["NO_STATIONID_FOUND"]) end else fibaro:debug("status:" .. status .. ", errorCode:" .. errorCode); end end sleepAndcheckslider = 0 while sleepAndcheckslider <= 20*updateEvery do fibaro:sleep(3000) WU.checkMobileOrWeb() sleepAndcheckslider = sleepAndcheckslider+1 if (DoNotRecheckBefore <= os.time()) and ((WU.scheduler == os.time) or (os.date("%H:%M") == WU.push_fcst1) or (os.date("%H:%M") == WU.push_fcst2)) then Debug("orange", WU.translation[WU.language]["Exiting_loop_push"]); DoNotRecheckBefore = os.time()+60 sleepAndcheckslider = 20*updateEvery end end end Debug( "orange", "WU Weather - Original LUA Scripting by Jonny Larsson 2015"); Debug( "orange", "YAMS WU - Fork by Sébastien Jauquet 11/2015"); Debug( "orange", "Version: "..WU.version); if WU.station == "LOCID" then locationID = WU.LOCID elseif WU.station == "PWS" then locationID = WU.PWS end if WU.CreateVG then WU.createGlobalIfNotExists("Meteo_Day", "") WU.createGlobalIfNotExists("Meteo_Tomorrow", "") WU.createGlobalIfNotExists("Meteo_In_2_Days", "") end while true do WU.fetchWU() end
  3. Watchdog Version 1.3 Voici une scène permettant de surveiller le fonctionnement des Scènes et Main Loop de Modules Virtuels sur Home Center 2 en version 4.x. Pour ce faire, les messages de la fenêtre de Debug sont analysés. De plus, pour les scènes uniquement, le nombre d'instances est compté. En cas de problème détecté, la scène ou le virtual device considéré est automatiquement redémarré, et une notification peut être envoyée. Copier/coller le script LUA suivant dans une nouvelle scène : --[[ %% autostart %% properties %% globals --]] -------------------------------------------------- -- Scene : Watchdog -- Author : Lazer -- Version : 1.3 -- Date : June 2017 -------------------------------------------------- -- User variables local intervalle = 60 local delay = 15*60 local watchdog = { } local userID = {} -- Email local smartphoneID = {} -- Push local sms = { ["VD_ID"] = 0, -- Virtual Device ID ["VD_Button"] = "1", -- Virtual Device Button ["VG_Name"] = "SMS" -- Global Variable Name } local debug = false -- -- Message function -- function Message(color, message) if color and color ~= "" then fibaro:debug('<span style="color:'..color..';">'..(message or '<nil>')..'</span>') else fibaro:debug(message or '<nil>') end end -- -- Notification function -- function Notification(message, param) local message = message or "<vide>" Message("yellow", "Notification : "..message) if param then for _, notif in ipairs(param) do if debug then Message("grey", notif) end -- Envoi Push if notif == "push" and smartphoneID then for _, id in ipairs(smartphoneID) do if debug then Message("grey", "Send Push smartphone ID : "..id) end fibaro:call(id, "sendPush", message) end -- Envoi Email elseif notif == "email" and userID then for _, id in ipairs(userID) do if debug then Message("grey", "Send Email user ID : "..id) end fibaro:call(id, "sendEmail", "HC2 Watchdog", message) end -- Envoi SMS elseif notif == "sms" and sms then if debug then Message("grey", "Send SMS : VD_ID="..(sms["VD_ID"] or 0).." VD_Button="..(sms["VD_Button"] or "0").." VG_Name="..(sms["VG_Name"] or "")) end fibaro:setGlobal(sms["VG_Name"], message) if sms["VD_ID"] and tonumber(sms["VD_ID"])>0 and sms["VD_Button"] and tonumber(sms["VD_Button"])>0 then fibaro:call(sms["VD_ID"], "pressButton", sms["VD_Button"]) end end end else Message("orange", "Warning : no notification options given") end end -- -- Restart function -- function Restart(type, id, restart, notification, reason) Message("blue", 'Restart '..type..'('..id..')') -- Prepare API URL local getURL = "" local putURL = "" if type:lower() == "scene" then getURL = 'http://127.0.0.1:11111/api/scenes/'..id putURL = 'http://127.0.0.1:11111/api/scenes/'..id elseif type:lower() == "vd" then getURL = 'http://127.0.0.1:11111/api/virtualDevices/'..id putURL = 'http://127.0.0.1:11111/api/virtualDevices/'..id end -- Load VD/Scene local httpClient = net.HTTPClient() httpClient:request(getURL, { success = function(response) if response.status == 200 then local jsonTable = json.decode(response.data) local name = jsonTable.name or "" if restart and restart == true then -- Add new line at end of scene lua code if type:lower() == "scene" and jsonTable.lua then jsonTable.lua = jsonTable.lua .. "\n" response.data = json.encode(jsonTable) end -- Save VD/Scene httpClient:request(putURL, { success = function(response) if response.status == 200 then Message("green", type.."("..id..") successfully restarted") Notification('Watchdog : '..type..' « '..(name or "")..' » ('..id..") a été redémarré : "..(reason or "???"), notification) else Message("red", type.."("..id..") Error : status="..tostring(response.status)) Notification('Watchdog : '..type..' « '..(name or "")..' » ('..id..") n'a pas pu être redémarré : "..(reason or "???"), notification) end end, error = function(err) Message("red", type.."("..id..") Error : "..err) Notification('Watchdog : '..type..' « '..(name or "")..' » ('..id..") n'a pas pu être redémarré : "..(reason or "???"), notification) end, options = { method = 'PUT', -- headers = { -- ["content-type"] = 'application/x-www-form-urlencoded;' -- }, data = response.data } }) else Notification('Watchdog : '..type..' « '..(name or "")..' » ('..id..") doit être redémarré manuellement : "..(reason or "???"), notification) end else Message("red", type.."("..id..") Error : status="..tostring(response.status)) Notification('Watchdog : '..type..' ('..id..") n'a pas pu être redémarré : "..(reason or "???"), notification) end end, error = function(err) Message("red", type.."("..id..") Error : "..err) Notification('Watchdog : '..type..' ('..id..") n'a pas pu être redémarré : "..(reason or "???"), notification) end, options = { method = 'GET' } }) end -- function -- -- Check function -- function Check(interval) Message(nil, "Check") -- Browse VD/Scene list local httpClient = net.HTTPClient() local elements = #watchdog for i = 1, elements do -- Initialization local countscene_found = false if debug then Message(nil, "Check : type="..watchdog[i].type.." id="..watchdog[i].id) end -- Check number of running scene instances if watchdog[i].type:lower() == "scene" and watchdog[i].count and watchdog[i].count > 0 then local countScenes = fibaro:countScenes(watchdog[i].id) if countScenes < watchdog[i].count then Message("orange", watchdog[i].type..'('..watchdog[i].id..') '..countScenes..' running instance') countscene_found = true Restart(watchdog[i].type, watchdog[i].id, watchdog[i].restart, watchdog[i].notification, countScenes..' instance') elseif debug then Message("green", watchdog[i].type..'('..watchdog[i].id..') '..countScenes.." running instance") end end if countscene_found == false then -- Do not enter this loop if scene has already been restarted -- Prepare API URL local getURL = "" if watchdog[i].type:lower() == "scene" then getURL = "http://127.0.0.1:11111/api/scenes/"..watchdog[i].id.."/debugMessages" elseif watchdog[i].type:lower() == "vd" then getURL = "http://127.0.0.1:11111/api/virtualDevices/"..watchdog[i].id.."/debugMessages/0" else Message("red", "Error : unknown type value") end if getURL ~= "" then if debug then Message("grey", getURL) end -- Load VD/Scene debug messages httpClient:request(getURL, { success = function(response) if response.status == 200 then if response.data and response.data ~= "" then local jsonTable = json.decode(response.data) local current_timestamp = os.time() local oldest_timestamp = current_timestamp local match_found = false local no_match_found = false local reason = "" -- Reverse browsing of debug messages for j = #jsonTable, 1, -1 do oldest_timestamp = jsonTable[j].timestamp -- Check if debug message match lookup string within allowed interval if watchdog[i].match.text and watchdog[i].match.text ~= "" and watchdog[i].match.interval > 0 and jsonTable[j].txt:match(watchdog[i].match.text) then if jsonTable[j].timestamp > current_timestamp - watchdog[i].match.interval then if debug then Message("green", watchdog[i].type..'('..watchdog[i].id..') Found string "'..watchdog[i].match.text..'"') end match_found = true end end -- Check if debug message match forbidden string if watchdog[i].no_match.text and watchdog[i].no_match.text ~= "" and jsonTable[j].txt:match(watchdog[i].no_match.text) then Message("orange", watchdog[i].type..'('..watchdog[i].id..') Found string "'..watchdog[i].no_match.text..'"') no_match_found = true reason = os.date('%H:%M:%S', (jsonTable[j].timestamp or 0)) .. " " .. jsonTable[j].type .. " : " .. jsonTable[j].txt break end if watchdog[i].no_match.type and watchdog[i].no_match.type ~= "" and jsonTable[j].type == watchdog[i].no_match.type then Message("orange", watchdog[i].type..'('..watchdog[i].id..') Found type "'..watchdog[i].no_match.type..'"') no_match_found = true reason = os.date('%H:%M:%S', (jsonTable[j].timestamp or 0)) .. " " .. jsonTable[j].type .. " : " .. jsonTable[j].txt break end end -- for if debug and oldest_timestamp > current_timestamp - watchdog[i].match.interval then Message("grey", watchdog[i].type..'('..watchdog[i].id..') oldest debug timestamp more recent than interval') end -- Restart VD/Scene if watchdog[i].match.text and watchdog[i].match.text ~= "" and watchdog[i].match.interval > 0 and match_found == false and oldest_timestamp < current_timestamp - watchdog[i].match.interval then Message("orange", watchdog[i].type..'('..watchdog[i].id..') String "'..watchdog[i].match.text..'" not found') reason = 'Chaine « ' .. watchdog[i].match.text .. ' » non trouvée' if #jsonTable > 0 then reason = reason .. ', dernier message : ' .. os.date('%H:%M:%S', (jsonTable[#jsonTable].timestamp or 0)) .. ' « ' .. (jsonTable[#jsonTable].txt or "<nil>") .. ' »' end Restart(watchdog[i].type, watchdog[i].id, watchdog[i].restart, watchdog[i].notification, reason) --if watchdog[i].no_match.text and watchdog[i].no_match.text ~= "" and no_match_found == true then elseif no_match_found == true then Restart(watchdog[i].type, watchdog[i].id, watchdog[i].restart, watchdog[i].notification, reason) end else Message("red", "Error : empty response") end else Message("red", "Error : status=" .. tostring(response.status)) end end, error = function(err) Message("red", 'Error : ' .. err) end, options = { method = 'GET' } }) end end end -- for -- Wait if interval and interval > 0 then setTimeout(function() Check(interval) end, interval*1000) end end -- function -- -- Main loop -- local trigger = fibaro:getSourceTrigger() if trigger["type"] == "autostart" then Message(nil, "Watchdog instance autostart") -- Check function call delayed to prevent killing all other scenes not already started right after HC2 boot setTimeout(function() Check(intervalle) end, delay*1000) else Message(nil, "Watchdog instance manual launch") -- Call Check function Check(nil) end . Le paramétrage du script s'effectue dans les quelques lignes situées sous le commentaire "User variables" : intervalle : durée entre 2 vérifications delay : délai avant la première vérification. En effet, cette scène ayant la propriété autostart afin de démarrer automatiquement au boot de la box, le risque est de démarrer avant les autres Scène/VD, et de forcer un redémarrage de ceux-ci alors qu'ils n'ont pas encore effectivement démarré. Ce délai laisse donc aux autres Scène/VD le temps de démarrer et de s'initialiser proprement. watchdog : tableau dont chaque ligne représente une Scène ou un Virtual Device à monitorer : type : "Scene" ou "VD" id : valeur numérique représentant l'ID de la Scène ou VD à monitorer match : texte qui doit être trouvé pendant un certain laps de temps afin de confirmer le bon fonctionnement du VD/Scène. Cela correspond typiquement à un message affiché cycliquement à intervalle régulier. Les 2 champs suivants doivent être renseignés pour que la condition soit prise en compte (condition ET) : text : chaine de caractères à trouver interval : durée en secondes no_match : texte qui ne doit pas être trouvé, sous peine de considérer le VD/Scène comme planté. Cela correspond typiquement à un message d'erreur LUA qui entraine le plantage du script. A noter que la condition no_match à priorité sur la condition match, c'est à dire que si le texte recherché par no_match est détecté, le VD/Scène sera redémarrer même si le texte recherché par match a été détecté. L'un ou l'autre des 2 champs suivants peuvent être renseignés pour que la condition soit prise en compte (condition OU) : text : chaine de caractères à trouver type : "ERROR" correspond aux messages affichés en rouge dans la fenêtre de Debug de l'interface HC2. A noter que jusqu'en v4.056, dans une scène une erreur LUA affichait le message en rouge avec le type "ERROR", tandis que depuis les Beta v4.057 et v4.058, cette même erreur s'affiche en blanc sans le type ERROR, par conséquent ce test ne fonctionne plus. En revanche, aucun changement de mode de fonctionnement concernant les Virtual Devices. count : valeur valable pour les scènes uniquement, et indiquant le nombre minimal d'instances qui doivent fonctionner pour confirmer le bon fonctionnement de la scène. Cela correspond typiquement à l'instance de type boucle infinie lancée en autostart. restart : true ou false afin de redémarrer le VD/Scène concerné, ou seulement envoyer une notification signalant qu'il faut le redémarrer manuellement. notification : liste séparée par des virgules des moyens de notifications à employer. userID : liste séparée par des virgules des ID des utilisateurs qui doivent recevoir des notifications par email (le mail est celui configuré pour chaque utilisateur dans le panneau de contrôle d'accès) smartphoneID : liste séparée par des virgules des ID des smartphones qui doivent recevoir des notifications push (à récupérer dans le toolkit de Krikroff ou via l'API : /api/iosDevices) sms : si vous avez une passerelle SMS sous Android avec SMS Gateway (ou équivalent) pilotée par un module virtuel, il faut renseigner ici les informations nécessaires : VD_ID : ID du module virtuel VD_Button : ID du bouton du module virtuel VG_Name : nom de la variable globale debug : true ou false afin d'activer l'affichage étendu dans la fenêtre de débugage de la scène. Exemple de paramètres : -- User variables local intervalle = 60 local delay = 15*60 local watchdog = { {type = "Scene", id = 1, match = {text="", interval=0}, no_match = {text=""}, count=1, restart=true, notification = {"push", "email", "sms"}}, -- Présence Lazer {type = "Scene", id = 2, match = {text="Last run", interval=2*60}, no_match = {text=""}, count=1, restart=true, notification = {"push", "email", "sms"}}, -- DomoCharts {type = "Scene", id = 3, match = {text="Durée des traitements", interval=11*60}, no_match = {text=""}, count=1, restart=true, notification = {"push", "email", "sms"}}, -- GEA {type = "VD", id = 1, match = {text="", interval=0}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- Surveillance Station {type = "VD", id = 2, match = {text="", interval=0}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- Clock Sync {type = "VD", id = 3, match = {text="", interval=0}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- My Batteries {type = "VD", id = 4, match = {text="", interval=0}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- Evénements {type = "VD", id = 5, match = {text="", interval=0}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- Network Monitor {type = "VD", id = 6, match = {text="", interval=0}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- GEA Alarm {type = "VD", id = 7, match = {text=" ", interval=30}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}}, -- Sonos Player (Tk.isTraceEnabled = true) {type = "VD", id = 8, match = {text="Start main process", interval=31*60}, no_match = {text="", type="ERROR"}, restart=true, notification = {"push", "email", "sms"}} -- Freebox Serveur } local userID = {1} -- Email local smartphoneID = {1, 2} -- Push local sms = { ["VD_ID"] = 99, -- Virtual Device ID ["VD_Button"] = "1", -- Virtual Device Button ["VG_Name"] = "SMS" -- Global Variable Name } local debug = false
  4. jojo

    My Batteries

    @flamalex a fait une modification au code car problèmes à partir du firmware v'.140ou v 4.145. Il l'a baptisée v2, mas comme on était déjà à v5.4, je l'ai rebaptisé v6.0. My_Batteries_v6.2.vfib My_Batteries_v6.1.vfib My_Batteries_v6.0.vfib --------------------------------------------------------------------------------------------------------------- My Batteries Ce virtual device permet de visualiser le niveau des batteries de l'ensembles de vos appareils sur batterie (max 10). Il est TRES largement inspiré du travail initial de Steven http://www.domotique-fibaro.fr/index.php/topic/1710-my-batteries/ Merci également à Moicphil qui m'a énormément aidé pour debugger la partie v4.x Les modifications que j'y ai apportées : modification de l'affichage, avec moment du dernier check automatique incorporation des supers icônes de @couillerot firmware 4.x push si batterie sous un certain niveau Voici la dernière version du VD : My_Batteries_v5.4.vfib Et les codes : MyBatteries.Batteries.lua MyBatteries.MainLoop.lua
  5. OJC

    Heating Manager

    HEATING MANAGER v. 3.1.2 - 16/12//2017 Heating Manager est un programme permettant d'utiliser le Home Center 2 pour gérer avec une grande souplesse le chauffage d'une habitation, en permettant de franchir une étape supplémentaires dans la gestion de celui-ci. En effet, s'il est parfaitement capable de fonctionner en suivant une planification, Heating Manager permet de passer à l'étape suivante et d'exploiter pleinement les potentialités de la domotique en se passant totalement de planification et en gérant le chauffage sur une base événementielle exclusivement dynamique. Heating Manager, qui propose de réguler le chauffage sur un mode proportionnel avec prise en compte des déperditions (Ubat) ou sur un mode classique avec hystérésis, est compatible avec n'importe quel système de commande de chauffage, y compris des modules virtuels. Il peut fonctionner en tout ou partie en mode planification via l'utilisation des panneaux de chauffage natifs du Home Center 2, de modules dédiés ou de variables globales. En mode événementiel, il peut s'appuyer sur n'importe quelle propriété de n'importe quel module, virtuel ou non, ainsi que sur des variables globales. L'utilisation de boucles conditionnelles dans la configuration permet en outre de faire varier cette configuration en fonction de n'importe quelle condition. Ces développements doivent beaucoup aux échanges stimulants intervenus sur ce fil de discussion, qui m'ont amené à aller bien plus loin que ce qui était prévu au départ, à savoir simplement pouvoir utiliser les panneaux de chauffage avec les modules fils pilote proposés par Qubino... Que tous soient remerciés , ainsi que ceux qui relèvent des bugs et permettent d'améliorer le script. _ _ _ PRE-REQUIS Ce programme a été conçu et testé sur le Home Center 2 tournant avec le firmware v. 4.140. Il ne requiert aucun matériel particulier et peut s'adapter facilement à toutes les configurations. _ _ _ INSTALLATION 1. Pour une utilisation en tout ou partie en mode planification, il faut commencer par définir les plannings de chauffe souhaités. La première étape dans cette optique de fonctionnement est de définir un planning de chauffe dans lequel Heating Manager ira chercher la température de consigne à atteindre. Ce planning de chauffe peut être mis en place en utilisant les panneaux de chauffage fournis nativement par le Home Center 2. Attention cependant, un bug a été constaté, évoqué dans ce fil, entraînant l'absence de prise en compte du changement de température de consigne après minuit. Il peut également être mis en place en utilisant n'importe quel module virtuel ou bien celui, basique, fourni avec Heating Manager >>>> Heating_Provider.vfib Pour utiliser ce module virtuel, il faut adapter la configuration donnée en exemple à votre cas en modifiant, et en ajoutant le cas échéant, les étiquettes, chaque étiquette correspondant à une zone de chauffage. La définition du planning de chauffe pour chacun de ces zones intervient dans le main loop du module virtuel, dans la partie Configuration : HeatingManager:add(zone, day, time, temperature) zone correspond au nom d''une étiquette du module virtuel day est soit un ou plusieurs jours de la semaine (en anglais e.g. {"monday","friday"}), soit "weekday" (du lundi au vendredi), soit "weekend", soit "week" time est l''heure à laquelle la température de consigne devra être appliquée "hh:mm" temperature est la température de consigne devant être appliquée à compter de l''horaire défini juste avant Il est important que la construction du planning de chauffe soit faite de manière chronologique, le module virtuel ne faisant pas de tri chronologique, ce qui peut entraîner un comportement s'écartant de celui attendu. 2. Pour une utilisation en tout ou partie en mode événementiel, il faut importer un thermostat par pièce concernée >>>> Thermostat.vfib Ce module virtuel permet de définir la température de consigne (mode Confort et mode Economique) pour la pièce, de forcer l'un de ces deux modes ou de passer en mode manuel avec un minuteur permettant de retourner au mode automatique. Les ordres donnés par l'intermédiaire de ce module viruel l'emportent sur toute autre évènement défini dans la configuration de Heating Manager. Il faut juste mettre un module virtuel dans chaque pièce. Sa détection par Heating Manager se fait automatiquement. 3. [OPTIONNEL] Pour afficher de manière centralisée les températures de consigne en cours, il faut installer le module virtuel Heating Viewer >>>> Heating_Viewer.vfib Pour le bon fonctionnement de ce module, chaque pièce dont le chauffage est géré par Heating Manager doit avoir une étiquette, dont l'ID doit être le nom de cette pièce débarrassé de tous les accents, espaces et autres caractères exotiques. Ainsi, pour la pièce "Séjour Principal #1", l'ID de l'étiquette doit être "SejourPrincipal1". Les étiquettes inutilisées peuvent être supprimées, tout comme il peut être ajouté autant d'étiquettes que nécessaire. 4. Création d'une scène en mode Lua avec copier-coller du code >>>> Heating Manager - Scène.lua La configuration de Heating Manager est réalisée par l'exécution de neuf fonctions différentes à paramétrer dans la partie USER CONFIGURATION ZONE qui se trouve à partir de la ligne 100 du code. self:setConfiguration(checkConfig, oldLastTempUpdate, logInfo, pushWarnErrLog, pushTo, popupWarnErrLog, logMemory) checkConfig est un booléen dont la valeur par défaut est true, qui permet de définir si Heating Manager doit contrôler de manière approfondie la configuration (existence des pièces, des modules, des propriétés de modules, des variables globales, etc.) Une fois que votre configuration est rodée et fonctionne sans problème, vous pouvez passer ce paramètre à false. oldLastTempUpdate est un nombre dont la valeur par défaut est 180 et qui est le nombre de minutes depuis la dernière remontée de température d'une sonde intérieure au-delà duquel Heating Manager adressera un message d'alerte et arrêtera la chauffe. logInfo est un booléen dont la valeur par défaut est true et qui permet de définir si l'intégralité des messages doit s'afficher dans la fenêtre de debug, ou uniquement les plus importants (action, survenance d'un événement, changement de la température de consigne). pushWarnErrLog est un booléen dont la valeur par défaut est false et qui permet de définir si les messages d'alerte et d'erreur doivent faire l'objet d'une notification Push. pushTo est une table contenant l'ID des téléphones mobiles auxquels envoyer les notification Push si le paramètre précédent est à true. popupWarnErrLog est un booléen dont la valeur par défaut est false et qui permet de définir si les messages d'alerte et d'erreur doivent faire l'objet d'une notification dans le centre de notification du Home Center 2. logMemory est un booléen dont la valeur par défaut est true et qui permet d'afficher dans la fenêtre de debug, toutes les cinq minutes, la mémoire utilisée par Heating Manager. self:setProportionalMode(default_kP, auto_kP, default_kT, cycle, minCycle, defaultSetpoint) Cette fonction ne doit être utilisée que si vous souhaitez utiliser le mode de régulation proportionnel. default_kP est un nombre dont la valeur par défaut est 60 et qui est le coefficient proportionnel utilisé par Heating Manager dans le cadre de la régulation proportionnelle si aucun coefficient particulier n'est défini pour un radiateur donné. auto_kP est un booléen dont la valeur par défaut est true et qui permet de définir si Heating Manager doit adapter le coefficient proportionnel en fonction de l'expérience acquise lors des cycles de chauffe. default_kT est un nombre dont la valeur par défaut est 1 et qui est le coefficient de déperditions thermiques (Ubat) utilisé par Heating Manager dans le cadre de la régulation proportionnelle si aucun coefficient particulier n'est défini pour un radiateur donné. La valeur 1 correspond à une maison bien isolée. Pour un bâtiment mal isolé, ce coefficient peut être fixé à 3. cycle est un nombre dont la valeur par défaut est 15 et qui est la durée d'un cycle de chauffage en minutes, au sein duquel s'insère la période de chauffe calculée par Heating Manager. minCycle est un nombre dont la valeur par défaut est 1 et qui est la durée minimale en minutes d'une période de chauffe. defaultSetpoint est soit comfort, soit eco (sans guillemets) et permet de déterminer, uniquement pour un fonctionnement en mode événementiel, si la consigne à appliquer en dehors de tout événement est la température de confort définie dans le thermostat virtuel ou la température économique. La valeur par défaut est comfort. self:setHysteresisMode(hysteresis, cycle, defaultSetpoint) Cette fonction ne doit être utilisée que si vous souhaitez utiliser le mode de régulation par hystérésis. hysteresis est un nombre dont la valeur par défaut est 0 et qui est l'écart en degré entre la température courante et la température de consigne au-delà ou en-deça duquel le chauffage sera démarré. cycle est un nombre dont la valeur par défaut est 15 et qui est l'intervalle en minutes entre deux comparaisons de la température courante et de la température de consigne. defaultSetpoint est soit comfort, soit eco (sans guillemets) et permet de déterminer, uniquement pour un fonctionnement en mode événementiel, si la consigne à appliquer en dehors de tout événement est la température de confort définie dans le thermostat virtuel ou la température économique. La valeur par défaut est comfort. self:setEventDefaults(eCumulative, eSetpoint, eDuration, eStep, ePersistence) eCumulative est un booléen dont la valeur par défaut est true et qui permet de définir si les conditions d'un événement doivent toutes être réalisés pour que l'événement soit considéré comme survenu, ou si la réalisation d'une seule condition est suffisante. Il s'agit ici de définir la valeur par défaut qui sera utilisée à défaut de paramétrage contraire lors du paramétrage de chaque événement. eSetpoint est un nombre dont la valeur par défaut est 18 et qui permet de définir la température de consigne qui sera appliquée par défaut en cas de survenance d'un événement lorsqu'aucune température de consigne propre n'est définie lors du paramétrage de l'événement. eDuration est un nombre dont la valeur par défaut est 0 et qui permet de définir la durée en minutes devant s'écouler entre la survenance de l'événement et l'application de la température de consigne correspondante, permettant ainsi de prévoir une diminution ou une augmentation graduelle de la température de consigne. eStep est un nombre dont la valeur par défaut est 0.5 et qui permet de définir les étapes de diminution ou d'augmentation graduelle de la température de consigne. ePersistence est un nombre dont la valeur par défaut est 0 et qui permet de définir la durée par défaut pendant laquelle Heating Manager continuera à considérer qu'un événement est réalisé à partir de l'instant où les conditions de sa réalisation ne sont plus remplies. Si les conditions sont à nouveau remplies pendant le délai de persistence, Heating Manager agira comme si elles n'avaient jamais cessé d'être remplies. self:addHeater(idRoom, idHeater, idSonde, localkP, localkT) Cette fonction permet de déclarer les radiateurs qui seront gérés par Heating Manager. La fonction doit être paramétrée pour chaque radiateur. idRoom est l'ID de la pièce définie dans le Home Center 2 dans laquelle se trouve le module de commande du radiateur. idHeater désigne un module de commande d'un radiateur sous forme de table {ID du module, instruction pour mise en route, instruction pour arrêt, valeur à l'arrêt} : ID du module est l'ID d'un module, virtuel ou non, permettant de commander la mise en route ou l'arrêt du chauffage. instruction pour mise en route est soit la commande à transmettre s'il s'agit d'un module 'réel' ("turnOn" par exemple), soit le numéro d'ordre du bouton d'un module virtuel. instruction pour arrêt est soit la commande à transmettre s'il s'agit d'un module 'réel' ("turnOff" par exemple), soit le numéro d'ordre du bouton d'un module virtuel. valeur à l'arrêt est la valeur de la propriété value lorsque le radiateur est arrêté, et est utilisé pour éviter d'envoyer les commandes de mise en route et d'arrêt inutilement. idSonde désigne une sonde de température qui peut être définie spécifiquement pour un radiateur s'il n'est pas asservi à la sonde de température principale de la pièce définie dans le Home Center 2. Il peut s'agir d'une sonde de température proprement dite ou d'un module virtuel et sera dans tous les cas sous la forme {ID du module, nom de la propriété contenant la température}. Il peut également s'agir du nom d'une variable globale dans laquelle est stockée la température. localkP permet de définir un coefficient proportionnel fixe qui sera utilisé pour calculer la commande de chauffe de ce radiateur. localkT permet de définir un coefficient de déperditions thermiques qui sera utilisé pour calculer la commande de chauffe de ce radiateur. self:addEvent(idRoom, idEvent, conditions, cumulative, setpoint, duration, persistence) Cette fonction permet de définir les événements qui entraîneront une modification de la température de consigne (ouverture d'une fenêtre, absence temporaire ou prolongée, lumière allumée ou éteinte...). idRoom est l'ID de la pièce concernée par l'événement, ou une table contenant les IDs de plusieurs pièces concernées par l'événement. idEvent est le nom de l'événement, qui sera affiché dans la fenêtre de debug lors de sa survenance. conditions est une table contenant les différentes conditions devant être réalisées, ensemble ou séparément, pour que l'événement soit considéré comme survenu et la température de consigne modifiée en conséquence. Cette table contient elle-même une table par condition (il y a donc forcément une double accolade au début et à la fin), sous la forme {nom de variable globale, opérateur ("==", "~=", ">=", "<=", ">", "<"), valeur à vérifier, durée en minutes devant s'être écoulée depuis que le résultat de la comparaison est vrai} ou {ID d'un module, nom de la propriété d'un module, opérateur ("==", "~=", ">=", "<=", ">", "<"), valeur à vérifier, durée en minutes devant s'être écoulée depuis que le résultat de la comparaison est vrai}. cumulative est un booléen permet de définir, pour cet événement particulier, si sa survenance implique la réalisation de toutes les conditions ou si une seule est suffisante. setpoint permet de définir la température de consigne devant être appliquée lorsque l'événement survient. Dans le cadre du mode de fonctionnement événementiel, vous pouvez utiliser les variables comfort et eco qui font références aux températures définies pour la pièce avec le module virtuel Thermostat. duration est la durée en minutes devant s'écouler entre la survenance de l'événement et l'application de la température de consigne correspondante, permettant ainsi de prévoir une diminution ou une augmentation graduelle de la température de consigne. persistence est un nombre qui permet de définir la durée pendant laquelle Heating Manager continuera à considérer que l'événement est réalisé à partir de l'instant où les conditions de sa réalisation ne sont plus remplies. Si les conditions sont à nouveau remplies pendant le délai de persistence, Heating Manager agira comme si elles n'avaient jamais cessé d'être remplies. Dans le cadre de la configuration, cette fonction peut s'insérer dans une boucle conditionnelle permettant de ne laisser l'événement se réaliser que sous des conditions précises, par exemple d'horaires. self:addGlobalEvent(idEvent, conditions, cumulative, setpoint, duration, persistence) Cette fonction permet de définir un événement s'appliquant à toutes les pièces dont le chauffage est géré par Heating Manager, et se configure exactement de la même manière que la précédente, le paramètre idRoom en moins. Attention : le fait que l'événement soit global ne signifie pas qu'il l'emporte sur les événements spécifiques d'une pièce. Heating Manager contrôle les événements les uns à la suite des autres pour chaque pièce, dans l'ordre de leur configuration. Dès que les conditions d'un événement sont remplies, le programme cesse la boucle et n'analyse pas les autres événements déclarés. self:setIndoorSonde(idRoom, idSonde) Cette fonction permet de définir la sonde de température d'une pièce si vous ne souhaitez pas utiliser la sonde de température principale définie dans le Home Center 2. idRoom est l'ID de la pièce concernée. idSonde désigne une sonde de température proprement dite ou un module virtuel et sera dans tous les cas sous la forme {ID du module, nom de la propriété contenant la température}. Il peut également s'agir du nom d'une variable globale dans laquelle est stockée la température. self:setSetpoint(idRoom, idSetpoint) Cette fonction permet de définir, pour une pièce donnée, la source de la température de consigne qui devra être appliquée. L'utilisation de cette fonction n'est requise que dans le cas de l'utilisation du mode planification, et est inutile lorsque le chauffage de la pièce est effectué selon le mode événementiel. idRoom est l'ID de la pièce concernée. idSetpoint désigne la source de la température de consigne et peut être : l'ID d'un panneau de chauffage natif du Home Center 2. une table sous la forme {ID du module, propriété du module contenant la température de consigne} s'il s'agit d'un module, virtuel ou non. le nom d'une variable globale qui contiendra la température de consigne. self:setOutdoorSonde(idSonde) Cette fonction permet définir une sonde de température extérieure. Elle n'est utilise que dans le cas de la régulation proportionnelle qui tient compte de la température extérieure, et est inutile pour une régulation à base d'hystérésis. idSonde désigne une sonde de température proprement dite ou un module virtuel et sera dans tous les cas sous la forme {ID du module, nom de la propriété contenant la température}. Lorsqu'aucune sonde de température extérieure n'est définie et que le mode de régulation proportionnel est utilisé, Heating Manager utilise la température fournie par le plugin Météo. 5. Mise à jour depuis une version précédente Cette nouvelle version apporte des modifications en profondeur du programme et de la manière de le configurer. Il n'est donc pas possible de faire simplement un copier-coller de la configuration d'une version précédente à la 3.0, qui était éclatée entre la scène et un module virtuel, mais il est nécessaire de reprendre la configuration depuis le départ. Depuis la version 3.0, il est impératif de modifier les fonctions self:addEvent pour ajouter dans les conditions le paramètre operator : "==", "~=", ">=", "<=", ">" ou "<". Si le contrôle de configuration est activé, un message d'erreur s'affichera dans la fenêtre de debug sans faire planter le programme. L'ajout du paramètre ePersistence dans la fonction self:setConfiguration et persistent dans les fonctions self:addEvent n'est pas indispensable puisqu'il s'agit du dernier paramètre de ces fonctions. A défaut de les ajouter, c'est la valeur par défaut (0) qui s'appliquera. _ _ _ ROADMAP [VIDE] _ _ _ ICONES
  6. Lazer

    Network Monitor

    Network Monitor Version 1.20 Voici un module virtuel permettant de surveiller plusieurs équipements sur le réseau local (et aussi sur Internet), et d'envoyer des notifications en cas de problème détecté. Icônes : Je propose ces 2 icônes, mais d'autres icônes sont disponibles dans les pages du topic : Configuration : Après import du module virtuel, modifier la section "User Variables" du 1er bouton du module virtuel : -- User variables local userID = {5} -- Mail local smartphoneID = {73, 127} -- Push local sms = { ["VD_ID"] = 98, -- Virtual Device ID ["VD_Button"] = "1", -- Virtual Device Button ["VG_Name"] = "SMS" -- Global Variable Name } local icons = { ["OK"] = 1028, -- Normal Icon ID ["Error"] = 1045 -- Error Icon ID } local DEVICES = { -- ["Service Name"] = { IP Address , Port, Protocol, Data to send, Expected return code, Expected data, Retry, {Notification methods}, VG, VG }, ["Eco-Devices"] = {"192.168.1.1", 80, "http", "/index1.htm", 200, "Eco Devices" , 1, {"push", "email", "sms"}, nil, nil}, ["HP ProLiant Remote Access Card"] = {"192.168.1.2", 80, "http", "/login.html", 200, "Remote Access Card" , 1, { "email" }, nil, {"Vacances", "1"}}, ["HP ProLiant Gen8 ILO"] = {"192.168.1.3", 443, "tcp", "", nil, "" , 1, { "email" }, nil, nil}, ["ESXi"] = {"192.168.1.4", 80, "http", "/", 301, "" , 1, {"push", "email", "sms"}, nil, nil}, ["Synology DiskStation"] = {"192.168.1.5", 5000, "http", "/webman/index.cgi", 200, "DiskStation" , 1, {"push", "email", "sms"}, nil, nil}, ["Raspberry PI"] = {"192.168.1.6", 80, "http", "/", 200, "Welcome to nginx" , 1, {"push", "email", "sms"}, nil, nil}, ["Sonos"] = {"192.168.1.7", 1400, "http", "/status", 200, "Options" , 1, {"push", "email" }, nil, {"Vacances", "1"}}, ["SMS Gateway"] = {"192.168.1.8", 9090, "http", "/", 200, "Welcome to SMS Gateway" , 5, {"push", "email" }, nil, nil}, ["VRT-IP"] = {"192.168.1.9", 80, "http", "/", 200, "Volets Roulant de Toit" , 1, {"push", "email" }, nil, nil}, ["IPX800"] = {"192.168.1.10", 80, "http", "/user/index2.htm", 200, "IPX800" , 1, {"push", "email" }, nil, nil}, ["Foscam"] = {"192.168.1.11", 88, "http", "/", 200, "IPCam Client" , 1, {"push", "email", "sms"}, nil, {"Vacances", "0"}}, ["Hikvision"] = {"192.168.1.12", 80, "http", "/doc/page/login.asp", 200, "login" , 1, {"push", "email", "sms"}, nil, nil}, ["HAproxy"] = {"192.168.1.13", 80, "http", "/", 503, "" , 1, {"push", "email", "sms"}, nil, nil}, ["FHEM"] = {"192.168.1.14", 8083, "http", "/fhem", 200, "EnOcean" , 1, {"push", "email", "sms"}, nil, nil}, ["Freebox"] = {"192.168.1.15", 80, "http", "/login.php", 200, "Freebox OS" , 1, { "sms"}, nil, nil}, ["OpenVPN"] = {"192.168.1.16", 443, "tcp", "", nil, "" , 1, { "email", "sms"}, nil, nil}, ["Redhat"] = {"192.168.1.17", 22, "tcp", nil, nil, "OpenSSH" , 1, { "email" }, nil, nil}, ["Google"] = {"www.google.fr", 80, "http", "/", 200, "Recherche Google" , 1, { "sms"}, nil, nil}} } local debug = false userID : liste séparée par des virgules des ID des utilisateurs qui doivent recevoir des notification par email (le mail est celui configuré pour chaque utilisateur dans le panneau de contrôle d'accès) smartphoneID : liste séparée par des virgules des ID des smartphones qui doivent recevoir des notifications push (à récupérer dans le toolkit de Krikroff ou via l'API : /api/iosDevices) sms : si vous avez une passerelle SMS sous Android avec SMS Gateway (ou équivalent) pilotée par un module virtuel, il faut renseigner ici les informations nécessaires. icons : si vous avez 2 icônes personnalisées, remplacer les valeurs nil par les ID numériques de vos icones (à trouver dans /api/icons) DEVICES : c'est la partie la plus longue à paramétrer, pour cela je vous ai laissé un exemple de tout ce que je monitore chez moi (j'ai juste changé les IP). C'est assez parlant, vous pouvez copier/coller en respectant bien la syntaxe. A noter que si l'avant-dernière colonne qui contient le nom facultatif d'une variable globale à incrémenter, celle-ci est automatiquement créée par le module. La dernière colonne permet d'annuler le monitoring d'un équipement particulier en fonction de la valeur d'une variable globale. debug : true ou false afin d'activer l'affichage étendu dans la fenêtre de débugage du bouton du module virtuel. Dans la Main Loop, le code est de Steven. Il y a une variable nbHeure permettant de paramétrer l'intervalle de vérification, par défaut à 1 heure. Si vous voulez un rafraichissement inférieur à 40 minutes, il suffit de tout remplacer par un simple fibaro:sleep(), car cette fonction ne plante pas pour les durées inférieures. Network_Monitor_v1.01.vfib Network_Monitor_v1.10.vfib Network_Monitor_v1.20.vfib
  7. Sunrisehour, Sunsethour, Os.date Et Variable Jour_Nuit V1.00 Une version plus élaborée ce trouve ici : http://www.domotique-fibaro.fr/scene-lua-jour-nuit-avec-decalge-possible-et-optimisation-du-sleep/ Au début j'ai utilisé le mode bloc pour mettre ma variable à jour. Un jour j'ai rencontré un soucis, la variable ne s'était pas mise a jour ? Pourquoi ? Tout simplement ma box était en cours de démarrage lorsque l'heure était égale a l'heure du coucher du soleil. Exemple : J'ai une coupe de courant de 18h00 à 19h00 Le coucher du soleil est a 18h24. Lorsque j'allume ma box a 19h00 la scène s'exécute bien mais comme l'heure de coucher du soleil et 18h24 elle ne met pas a jour la variable globale. J'ai donc décider de faire cela en LUA et dans une seul Scéne. Il me fallait : L'heure de lever du soleil fibaro:getValue(1, "sunriseHour") L'heure de coucher du soleil fibaro:getValue(1, "sunsetHour") L'heure Actuelle Var_Heure = os.date("%H:%M", os.time()) il me reste plus qu'à surveiller l'heure actuelle Et de la comparer avec le avec l'heure du coucher et du lever du soleil while true do local Var_Heure = os.date("%H:%M", os.time()) local Lever = fibaro:getValue(1, "sunriseHour") local Coucher = fibaro:getValue(1, "sunsetHour") if ( Var_Heure == Lever ) then fibaro:setGlobal("Jour_Nuit", "Jour"); elseif ( Var_Heure == Coucher ) then fibaro:setGlobal("Jour_Nuit", "Nuit"); else fibaro:debug("controle en cours") end fibaro:sleep(60*1000); end Avec ce code j'ai toujours le probléme si ma box et éteinte au moment du lever ou du coucher du soleil je vais donc ajouter ce code : if (os.date("%H:%M", os.time()) >= fibaro:getValue(1, "sunriseHour")) and (os.date("%H:%M", os.time()) < fibaro:getValue(1, "sunsetHour")) then fibaro:setGlobal("Jour_Nuit", "Jour"); else fibaro:setGlobal("Jour_Nuit", "Nuit"); end Je teste : Si l'heure et supérieur ou égal est inférieur a l'heure du coucher du soleil Si c'est le cas il fait Jour sinon il fait Nuit. On dispose de tout pour faire notre Scéne : (Version 1.0) --[[ %% autostart --]] -- Test du nombre de scènes en cours if (fibaro:countScenes() > 1) then fibaro:abort() end -- met la variable a jour au démarrage if (os.date("%H:%M", os.time()) >= fibaro:getValue(1, "sunriseHour")) and (os.date("%H:%M", os.time()) < fibaro:getValue(1, "sunsetHour")) then fibaro:setGlobal("Jour_Nuit", "Jour"); else fibaro:setGlobal("Jour_Nuit", "Nuit"); end -- se lance au démarrage et toutes les 60 secondes. while true do local Var_Heure = os.date("%H:%M", os.time()) local Lever = fibaro:getValue(1, "sunriseHour") local Coucher = fibaro:getValue(1, "sunsetHour") if ( Var_Heure == Lever ) then fibaro:setGlobal("Jour_Nuit", "Jour"); elseif ( Var_Heure == Coucher ) then fibaro:setGlobal("Jour_Nuit", "Nuit"); else fibaro:debug("controle en cours") end fibaro:sleep(60*1000); end Date et heure courante (os.date) http://www.luteus.biz os.date([format [, temps ] ]) Retourne dans une table des informations de date et heure formatté par une chaîne de caractère. La chaîne de caractère a le même format que la fonction strftime() de C. Les caractères suivants sont utilisés pour spécifier le format de la date : %a - nom abrégé du jour de la semaine (local) %A - nom complet du jour de la semaine (local) %b - nom abrégé du mois (local) %B - nom complet du mois (local) %c - représentation préférée pour les dates et heures, en local %C - numéro de siècle (l'année, divisée par 100 et arrondie entre 00 et 99) %d - jour du mois en numérique (intervalle 01 à 31) %D - identique à %m/%d/%y %e - numéro du jour du mois. Les chiffres sont précédés d'un espace (de ' 1' à '31') %g - identique à %G, sur 2 chiffres %G - L'année sur 4 chiffres correspondant au numéro de semaine (voir %V). Même format et valeur que %Y, excepté que si le numéro de la semaine appartient à l'année précédente ou suivante, l'année courante sera utilisé à la place %h - identique à %b %H - heure de la journée en numérique, et sur 24-heures (intervalle de 00 à 23) %I - heure de la journée en numérique, et sur 12- heures (intervalle 01 à 12) %j - jour de l'année, en numérique (intervalle 001 à 366) %m - mois en numérique (intervalle 1 à 12) %M - minute en numérique %n - caractère de nouvelle ligne %p - `AM' ou `PM', en majuscule, suivant la valeur donnée, ou la chaîne correspondante pour la locale courante %P - `am' ou `pm', en majuscule, suivant la valeur donnée, ou la chaîne correspondante à la locale courante %r - l'heure au format a.m. et p.m %R - l'heure au format 24h %S - secondes en numérique %t - tabulation %T - l'heure actuelle (égal à %H:%M:%S) %u - le numéro de jour dans la semaine, de 1 à 7. (1 représente Lundi) %U - numéro de semaine dans l'année, en considérant le premier dimanche de l'année comme le premier jour de la première semaine %V - le numéro de semaine comme défini dans l'ISO 8601:1988, sous forme décimale, de 01 à 53. La semaine 1 est la première semaine qui a plus de 4 jours dans l'année courante, et dont Lundi est le premier jour. (Utilisez %G ou %g pour les éléments de l'année qui correspondent au numéro de la semaine pour le timestamp donné.) %W - numéro de semaine dans l'année, en considérant le premier lundi de l'année comme le premier jour de la première semaine %w - jour de la semaine, numérique, avec Dimanche = 0 %x - format préféré de représentation de la date sans l'heure %X - format préféré de représentation de l'heure sans la date %y - l'année, numérique, sur deux chiffres (de 00 à 99) %Y - l'année, numérique, sur quatre chiffres %Z ou %z - fuseau horaire, ou nom ou abréviation (suivant le système d'exploitation) %% - un caractère `%' littéral Exemple : >os.date("%Y/%m/%d %H:%M:%S") '2010/03/04 09:05:16' Module Virtuel Coucher et Lever Soleil : Coucher-Lever_Jour.vfib
  8. HANSOLO

    Jour Chômé

    V2 du 27/06/2014 grandement amélioré par STEVEN Nouveautés de la V2: - Calcul si le jour en cours et jour +1 est chômé ou pas - Choix des jours fériés France ou Suisse - Ce qui change par rapport à la V1: ajout d'un label dans le module virtuel et ajout d'une variable globale JourChomeJ1, pour lancer le calcul depuis GEA ou SCHEDULER bouton 3 au lieu de 2 pour la version précédente. Objectif: calculer si le jour en cours est chômé (WE ou férié) ou pas et stocker le résultat dans une variable globale, le tout sans dépendre d'un agenda externe à la HC2 et de script intermédiaire. Il s'agit d'une légère adaptation du code pour la VERA LITE de josDBlog http://gurau-audibert.hd.free.fr/josdblog/2014/01/lua-vacances-jours-chomes-et-jours-feries/ 1er étape, dans le panneau des variables, créer deux variables globale prédéfinie JourChome JourChomeJ1 avec les valeurs prédéfinies OUI NON. 2 iém étape, créer un module virtuel avec deux labels et un bouton: Le détail: Et ci-dessous la code à coller dans le bouton du module virtuel: -- Retourne OUI si le jour courant et J+1 est un jour chômé (WE ou férié) -- Adapté de http://gurau-audibert.hd.free.fr/josdblog/2014/01/lua-vacances-jours-chomes-et-jours-feries/ -- Pour la HC2 par Hansolo -- V1 26/06/2014 Initié par HANSOLO -- V2 27/06/2014 Amélioré par STEVEN, gestion des JS SUISSE et calcul J et J+1 local france = true local suisse = false local geneve = false -- Retourne le jour de la semaine en clair function josdGetJourSemaine(jour) --fibaro:debug ("jour: ") josdGetJourSemaineTab={[0]="dimanche",[1]="lundi",[2]="mardi",[3]="mercredi",[4]="jeudi",[5]="vendredi",[6]="samedi"} return josdGetJourSemaineTab[tonumber(jour)] end -- Retourne le jour de Pâques au format epoch -- annee : année (Integer) dont on désire connaître le jour de Pâques (ex : 2014) function josdGetJourPaques(annee) local a=math.floor(annee/100); local b=math.fmod(annee,100); local c=math.floor((3*(a+25))/4); local d=math.fmod((3*(a+25)),4); local e=math.floor((8*(a+11))/25); local f=math.fmod((5*a+,19); local g=math.fmod((19*f+c-e),30); local h=math.floor((f+11*g)/319); local j=math.floor((60*(5-d)+b)/4); local k=math.fmod((60*(5-d)+,4); local m=math.fmod((2*j-k-g+h),7); local n=math.floor((g-h+m+114)/31); local p=math.fmod((g-h+m+114),31); local jour=p+1; local mois=n; josdGetJourPaquesAnnee=annee; josdGetJourPaquesEpochPaque=os.time{year=annee,month=mois,day=jour,hour=12,min=0}; return josdGetJourPaquesEpochPaque; end -- Retourne true si le jour courant est un jour férié function josdJourFerie(time) local today=os.date("%m-%d", time); local annee=tonumber(os.date("%Y", time)); -- Dates fixes josdJourFerieTab = {} local epochPaques=josdGetJourPaques(annee); if (france) then josdJourFerieTab["01-01"] = true; -- 1er janvier josdJourFerieTab["05-01"] = true; -- Fête du travail josdJourFerieTab["05-08"] = true; -- Victoire des alliés josdJourFerieTab["07-14"] = true; -- Fête nationale josdJourFerieTab["08-15"] = true; -- Assomption josdJourFerieTab["11-01"] = true; -- Toussaint josdJourFerieTab["11-11"] = true; -- Armistice josdJourFerieTab["12-25"] = true; -- Noà«l -- Dates variables josdJourFerieTab[os.date("%m-%d",epochPaques)] = true; -- Pâques josdJourFerieTab[os.date("%m-%d",epochPaques+24*60*60)] = true; -- Lundi de Pâques = Pâques + 1 jour josdJourFerieTab[os.date("%m-%d",epochPaques+24*60*60*39)] = true; -- Ascension = Pâques + 39 jours josdJourFerieTab[os.date("%m-%d",epochPaques+24*60*60*50)] = true; -- Pentecôte = Ascension + 50 jours end if (suisse) then josdJourFerieTab["01-01"] = true; -- 1er janvier josdJourFerieTab["08-01"] = true; -- Fête national josdJourFerieTab["12-25"] = true; -- Noà«l -- Dates variables if (geneve) then josdJourFerieTab[jeuneGenevois(time)] = true; -- jeunes genevois else josdJourFerieTab[jeuneFederal(time)] = true; -- jeunes genevois end josdJourFerieTab[os.date("%m-%d", epochPaques)] = true; -- Pâques josdJourFerieTab[os.date("%m-%d", epochPaques+24*60*60)] = true; -- Lundi de Pâques = Pâques + 1 jour josdJourFerieTab[os.date("%m-%d", epochPaques+24*60*60*39)] = true; -- Ascension = Pâques + 39 jours josdJourFerieTab[os.date("%m-%d", epochPaques+24*60*60*50)] = true; -- Pentecôte = Ascension + 50 jours josdJourFerieTab[os.date("%m-%d", epochPaques-48*60*60)] = true; -- Vendredi-saint = Pâques - 2 jour end return josdJourFerieTab[today]; -- (nldr : Both nil and false make a condition false) end -- Calcul le jeudi qui suit le 1er dimanche de septembre function jeuneGenevois(time) local jour = 1 local annee = tonumber(os.date("%Y", time)) while (os.date("%A", os.time{year=annee, month=9, day=jour}) ~= "Sunday") do jour = jour + 1 end return os.date("%m-%d", os.time{year=annee, month=9, day=(jour+4)}) end -- Calcul le lundi qui suit le 3ème dimanche de septembre function jeuneFederal(time) local jour = 1 local annee = tonumber(os.date("%Y", time)) while (os.date("%A", os.time{year=annee, month=9, day=jour}) ~= "Sunday") do jour = jour + 1 end return os.date("%m-%d", os.time{year=annee, month=9, day=(jour+15)}) end -- Affiche le résultat function display(jour, result, label, variable, time) selfId = fibaro:getSelfId() fibaro:debug ("Jour chomé: " .. result) -- Mise à jour de la variable globale if (variable) then fibaro:setGlobal(variable, result) end -- Mise à jour du label du module virtuel fibaro:call(selfId,"setProperty","ui."..label..".value", jour .. " " .. os.date("%d.%m.%Y ",time).." Jour chomé: ".. result) end -- Lancement du calcul function doCalculate(time, label, variable) local jour = josdGetJourSemaine(os.date("%w", time)) josdJourChomeReturn = (jour=="samedi" or jour=="dimanche" or josdJourFerie(time)) if josdJourChomeReturn then display(jour, "OUI", label, variable, time) else display(jour, "NON", label, variable, time) end end doCalculate(os.time(), "Label1", "JourChome") doCalculate(os.time()+24*60*60, "Label2", "JourChomeJ1") J’exécute le code tous les jours à 00H15 depuis le Scheduler (90 étant l'ID de mon module virtuel et 3 la position du bouton) ce qui évite d'utiliser le main loop du module virtuelle et d'éventuels problèmes. luaDaySchedule:add("00:15","90", 3 , "pressButton",{"All"},true) La même chose depuis GEA. GEA.add({"Global", "", ""}, 30, "", {{"VirtualDevice", 90, 3},{"Time", "00:00", "00:01"}}) Pour choisir les jours fériés France ou Suisse (au début du code) local france = oui local suisse = non local geneve = non Merci à STEVEN pour les améliorations. Voilà un truc tout simple que j'utilise pour gérer mes volets Correction du 13/07/2014, utiliser true ou false pour la sélection des calendriers des jours fériés local france = true local suisse = false local geneve = false Correction du 14/04/2015, calcul du jeudi de l’ascension erroné Correction du 03/05/2015, calcul du jeudi de l'ascension dans la partie Suisse Correction du 25/05/2015, calcul du lundi de pentcôte
  9. Barelle

    VD UPS

    Hello, Comme vous le savez, nos matériels électroniques n’apprécient pas du tout les coupures électriques. Pour cela, il est plus que recommandé d’utiliser un onduleur (ou UPS, "Uninterruptible Power Supply")… Le VD que je vous propose ici permet l’interrogation du serveur UPS résidant sur un NAS Synology (auquel l’onduleur est connecté par un port USB). Il met à jour une variable globale (appelée UpsStatus par défaut) avec les valeurs "power-line" ou "battery" selon que l’onduleur est sur secteur ou sur batterie. Cette variable globale permet le lancement de la scène ci-après qui : - lors d’un passage sur batterie, après le délai "delayBeforePowerOff" réalisera l’arrêt de la HC2 ; - lors du retour de l’alimentation, appuiera sur le bouton "WOL" du VD. Là aussi, le réveil se fera après un délai "delayBeforeWakeUp". Ces délais ont pour objet de s’affranchir de retours temporaires de tension. --[[ %% properties %% events %% globals UpsStatus --]] local globalVarName = "UpsStatus"; -- values "power-line" or "battery" local wolVdId = "337"; local wolVdBtnId = "11"; local delayBeforePowerOff = 5; -- minutes local delayBeforeWakeUp = 5; -- minutes local debug = true; function trace(text, color) color = color or "white"; if debug then fibaro:debug("<font color='"..color.."'>"..text.."</font>"); end end -- trace function tracerr(text, color) color = color or "red"; fibaro:debug("<font color='red'>ERROR! </font>".."<font color='"..color.."'>"..text.."</font>"); end -- tracerr function wakeOnLan() fibaro:call(wolVdId, "pressButton", wolVdBtnId); end -- wakeOnLan local sourceTrigger = fibaro:getSourceTrigger(); trace("sourceTrigger[type] = " .. sourceTrigger["type"], "deepskyblue"); if (sourceTrigger["type"] == "global") then if (sourceTrigger["name"] ~= globalVarName) then tracerr("unknown global "..sourceTrigger["name"].." exiting"); fibaro:abort(); end elseif (sourceTrigger["type"] == 'other') then trace("Scene triggered manually", "lightgreen"); -- inform user local upsStatus = fibaro:getGlobalValue(globalVarName); if (upsStatus ~= nil) then trace(globalVarName.." = "..upsStatus, "lightgreen"); fibaro:abort(); end else tracerr("unexpected trigger type ".. sourceTrigger["type"], "orange"); fibaro:abort(); end if (fibaro:countScenes() > 1) then trace("Script already running, exiting.", "green"); return; end local upsStatus = fibaro:getGlobalValue(globalVarName); if (upsStatus == nil) then tracerr("global "..globalVarName.." = nil"); fibaro:abort(); end if (upsStatus == "power-line") then local i = 0; for i = 1, (delayBeforeWakeUp * 6) do -- check every 10 seconds during delayBeforeWakeUp minutes fibaro:sleep(10 * 1000); -- ten seconds upsStatus = fibaro:getGlobalValue(globalVarName); if (upsStatus ~= "power-line") then trace("Still on battery, aborting", "orange"); fibaro:abort(); -- not stable end end -- Time to wake up devices trace("Waking up devices", "lightgreen"); wakeOnLan(); elseif (upsStatus == "battery") then local i = 0; for i = 1, (delayBeforePowerOff * 6) do -- check every 10 seconds during delayBeforePowerOff minutes fibaro:sleep(10*1000); -- ten seconds upsStatus = fibaro:getGlobalValue(globalVarName); if (upsStatus ~= "battery") then trace("Power is back, shut down aborted", "orange"); fibaro:abort(); end end -- shutdown HC2 gracefully trace("shutting down", "lightgreen"); fibaro:sleep(10*1000); HomeCenter.SystemService.shutdown(); else tracerr("global "..globalVarName.." unknown value: "..upsStatus); end Installation du VD : - Importer le VD, - Renseigner l’adresse IP du NAS connecté à l’onduleur, le port TCP 3493 est optionnel. - Les username et password présents dans le code du bouton Update fonctionnent pour un Synology. - Dans le code du bouton WOL, vous devrez préciser les adresses MAC des matériels que vous souhaitez réveiller. Il va de soi qu’ils devront être paramétrés pour accepter les "magic packets" afin d’être réveillés (pour les PC vérifier les paramètres de la carte réseau). - Pour les Nas Synology, il faut activer le WOL : "Panneau de configuration", "Matériel et alimentation", onglet "Général", cocher "Activer WOL sur le réseau local x". - Et ne pas oublier d’activer le serveur réseau UPS : "Panneau de configuration", "Matériel et alimentation", onglet "UPS", cocher "Activer la prise en "charge UPS" et "Activer le serveur réseau UPS"). - Enfin bien sûr, trouver une jolie icône pour les boutons du VD. Installation de la scène : - Préciser l’id du VD réalisant le WOL dans "wolVdId". - et le numéro du bouton à appuyer "wolVdBtnId". Pour ceux qui veulent personnaliser le VD, le code du bouton "Update" contient, à la fin, une description des principaux champs retournés par les serveurs UPS, Tous ne sont pas implémentés par Synology ou mon onduleur. Configuration utilisée pour les tests : - HC2 : 4.153 Beta - Onduleur : Eaton Ellipse PRO 1200 - NAS : Synology DS1010+ with DSM 5.2-5967 Update 6 Joyeux réveillon et bonne année à tous… UPS.vfib
  10. razowski

    Module Virtuel "hc2 - Diagnostics"

    Hello, Voici un petit module virtuel qui va interroger la HC2 et qui permet quand on est pas à la maison, de garder un oeil sur la mémoire utilisée par notre HC2, la charge CPU et l'espace disponible pour le système respectivement le recovery. Voici mon icône, si cela peut vous intéresser...: Voici le module virtuel : HC2_Diagnostics.vfib Pour que ça marche, importer le Virtual Device et c'est prêt. Bonne découverte. @+ Razowski
  11. Bonjour Pour mon premier tuto, je vous propose un Module Virtuel pour interfacer la Livebox d'Orange et je vais vous détailler la mise en Å“uvre de l'intégration avec la HC2. Le module rassemble les informations importantes sur l'état des interfaces, le débit, les statistiques et les différents compteurs d'erreurs. Il permet aussi d'exécuter des commandes simples comme l'activation du Wifi ou le redémarrage de la Livebox. Prérequis Une Livebox 2 (Sagem) DSL note: pas pu tester la fibre. J'aimerais bien mais dans moin coin c'est pas avant 2022 ). Une HC2 (code lua testé avec v3.600 et v4.031) Installation Télécharger et ajouter le VD (lien en bas de post) Sur la page de configuration du module, saisir l'adresse ip et le port (80) de la Livebox Ensuite, il faut paramtètrer le VD, editez le code en debut de page (pour chaque bouttons): -- Nom d'utilisateur et mot de passe de la livebox local USER ="admin" local PASSWORD = "admin" Le VD retourne trois états possibles: Inconnu, OK et Not OK. Editez les variables pour adapter l'ID des icones: -- ID des icônes icon_ok = 1004 icon_nok = 1005 icon_unknown = 1006 Par défault, l'execution du module toutes les 5 minutes est confié à la mainloop du VD qui simule un appui sur le bouton Rafraichir. Simple, mais pour plus de fléxibilité et surtout de plus stabilté je recommande d'utiliser l'excellent GEA avec la ligne ci-dessous (à adapter). Dans ce cas, noubliez pas de supprimer le code dans le mainloop du VD. -- Mise à jour état connexion Internet GEA.add(true , 5*60, "",{{"VirtualDevice", id["VD_LIVEBOX"], "1"},{"VirtualDevice", id["VD_LIVEBOX"], "7"},{"Repeat"}}) Le VD n'utilise pas de Variable Globale car je n'ai pas de scénario qui necessite un retour sur l'état de la connexion internet mais c'est juste une ligne de code à ajouter: fibaro:setGlobal('test', Livebox.WANStatus.LinkState) Comment ca marche ? c'est la section pour les geeks. Je partage ici le resultat de mes bidouilles (et saut d'humeur) à propos de l'API Livebox Fonctionnement de l'API Orange/Sagem: En regardant d'un peu plus près les paquets échangés dans une session d'admin avec la livebox on peut voir des réponses de POST en json . à‡a commence plutôt pas mal, la livebox a donc une API ! Comme souvent avec Orange, ça commence bien, c'est après que les choses se gâtent ! Impossible de mettre la main sur une doc publique de l'API. En fouillant un peu sur les forums d'Orange j'ai trouvé quelques pistes mais mes vrais amis ont été Wireshark et les dev tools InternetExplorer ou Chrome (F12) pour comprendre un peu comment l'appli mobile d'Orange (version IOS) utilisait l'API… En inspectant le déroulé d'un login, je manque de m'étrangler en constatant que le nom d'utilisateur et le mot de passe sont balancés en clair; ben voyons les gars faut pas se gêner hein… la requête login retourne un "ContextID" qui est utilisé comme identifiant pour les appels aux fonctions de l'API (X-Context dans les headers). Donc au menu nous avons des custom headers et une authentification super basique, fastoche! où est le problème? Bah ça marche pô! - > "permission denied" le voilà le problème Bah surement qu'ils ont été pris de remords chez Orange avec cette authentification de mickey avec password en clair et histoire de faire bonne figure (et pas se faire défoncer tous les mercredi par des pré-ados qui voudraient passer outre le contrôle parental) ils ont semble-t-il cherché à compliquer un peu les choses… mais en faisant du gros n'importe quoi! Pour aller à l'enssentiel, en plus d'un ContextID, le Login renvoie une autre clé mais planquée dans un cookie cette fois. La sécurité n'y a pas gagné grand chose mais en revanche c'est une vraie prise de tête à intégrer sur la hc2. Hmm.. Net.FHttp avec des custom headers et un cookie, ça va pas le faire… Pour contourner le problème et récupérer le cookie, je me suis servi du génialissime ToolKit v1.0.4 de Krikroff. Une toute petite modif de 4 lignes dans httpClient:request et nous voila prêts à nous goinfrer de cookies. J'ai modifié (à l'arrache, sorry Krikroff) la fonction request(...) dans le fichier Toolkit.net.lua (commence ligne 165). on cherche la chaine "cookie" dans les response headers renvoyés par le serveur et le cas échéant on extrait avec un string.sub() en partant du douzième char. la fonction retourne le cookie en plus des classiques response, status et err. request = (function(self, method, uri, headers, body) ... for k, v in pairs(__headers) do --Toolkit.Net.__trace("raw #"..k..":"..v) if (string.find(string.lower( v or ""), "chunked")) then self.__isChunked = true; Toolkit.Net.__trace("%s.%s::receive > Transfer-Encoding: chunked", Toolkit.Net.__header, Toolkit.Net.__Http.__header, string.len(result)); -- Modification pour récupérer le cookie. Ofwood Janvier 2015 elseif (string.find(string.lower( v or ""), "cookie")) then cookie = string.sub(v, 12) Toolkit.Net.__trace("%s.%s::receive > Cookie: %s", Toolkit.Net.__header, Toolkit.Net.__Http.__header, cookie); end end ... -- return budy response & cookie return response, status, err, cookie; Voyons maintenant avec un exemple comment tirer profit de cette modification et mangeons des cookies! La fonction login() authentifie l'utilisateur et retourne le contextID (dans la réponse json) et le cookie associé. function login() local httpClient = Toolkit.Net.HttpRequest(ip, port) httpClient:setReadTimeout(Livebox.commandTimeOut) local uri = string.format("/authenticate?username=%s&password=%s", utilisateur, mot_de_passe) local response, status, errorCode, cookie = httpClient:request("POST", uri, {"User-Agent: FibaroHC2/1.0", "Content-Type: application/json"}, "" ) if (errorCode == 0) and tonumber(status) == 200 then local jsonTable = json.decode(response); ContextID = jsonTable.data.contextID; return ContextID, cookie end end l'exemple suivant utilise le contextID et notre cookie pour une requête (l'état de l'interface WAN sur la LiveBox) function getWANStatus(contextID, cookie) local httpClient = Toolkit.Net.HttpRequest(ip, port) httpClient:setReadTimeout(Livebox.commandTimeOut) local uri = "/sysbus/NMC:getWANStatus" local params = [[ {"parameters":{}} ]]; -- Injection de X-Context et du Cookie dans les headers local response, status, errorCode, cookie = httpClient:request("POST", uri, {"User-Agent: FibaroHC2/1.0", "Content-Type: application/json", "X-Context: "..contextID, "Cookie: "..cookie }, params); if (errorCode == 0) and (status == 200) then local jsonTable = json.decode(response) Return jsonTable.result.data end end Voici la liste des fonctions implémentées dans la version 1.0 du module. Il en existe d'autres, je n'ai pas encore tout recensé. Livebox.login() Authentification session utilisateur Livebox.logout() Fermeture session Livebox.listTrunks() Information téléphonie IP Livebox.getIPTVStatus() Etat IP TV Livebox.getDSLStats() Stats DSL (Erreurs) Livebox.getMIBs() Information lien dsl Livebox.getWifiMIBs() Information Wifi Livebox.getWANStatus() Etat de la connexion WAN Livebox.reboot() Redémarrage la livebox Livebox.setwifi(mode) Active/désactive le Wifi Livebox.filtreMAC(flag) Active/Désactive filtrage MAC address Livebox.getWificomStatus() Information Wifi public Orange Voilà , ça donne l'idée générale et Orange n'ayant pas le monopole sur les APIs bien pourries, je me suis dit que ça pourrait peut-être en aider d'autres qui se prennent la tête sur des intégrations nécessitant le support des cookies. Enjoy! merci pour vos retours (et votre indulgence) Historique 13/01/2015 - v1.0 : version initiale Livebox_VD.zip
  12. Steven

    Evénements

    Evénements Module virtuel pour afficher les derniers événements Lorsque l'on fait des tests, il est parfois pratique d'avoir la liste des derniers événements ayant eu lieu sur notre HC2. Voici donc mon dernier module virtuel avant les vacances :-) Comme vous pouvez le voir, ce module affiche les 10 événements en oubliant volontairement les modules de températures. Si vous voulez voir plus d'événements, il vous faudra rajouter vous-même des labels en faisant juste attention que leur ID suivent la numérotation Label11, Label12, Label13, ... et modifier la position du bouton rafraîchir dans le Main Loop. J'ai volontairement ajouté la pièce pour certaine personne qui se reconnaîtrons Ce dernier affiche donc : Le nom du module concerné La pièce dans laquelle il se trouve Son ancienne valeur Sa nouvelle valeur L'heure de l'événement Ce module se rafraîchi automatiquement toutes les 3 secondes . . . Installation Il vous suffit juste d'importer le module virtuel ci-joint puis de modifier votre pseudonyme et mot de passe qui se trouve dans le bouton Rafraichir local user = "admin" local pwd = "password" HC2 = Net.FHttp("127.0.0.1",80) HC2:setBasicAuthentication(user, pwd) ... Cordialement Evenements.vfib
  13. Steven

    Pluviométrie Avec Netatmo

    PLUVIOMETRIE (ET ARROSAGE) AVEC NETATMO firmware 4.x seulement Partie 1 : récupérer l'historique Netatmo est une station météo sur laquelle vous pouvez brancher un "pluviomètre" de la même marque. Afin d'exploiter les données de ce pluviomètre et vous pouvez utiliser l'application Netatmo ou son site web. Vous pouvez aussi installer le plugin Netatmo fourni par Fibaro. Ce dernier vous affichera uniquement les données à l'instant précis ou vous être entrain de le regarder. Nous, nous voulons allez plus loin, nous voulons connaitre les quantités de pluie ayant eu lieu depuis : 1 jour, 1 semaine, 1 mois, cela dans l'optique de pouvoir gérer correctement notre arrosage. Pour ce faire, il existe un grand nombre de script PHP, Google Script qui permet de gérer cela .. mais ... depuis la v4.x, Fibaro nous fait bénéficier de la librairie net.httpClient dans une scène et cette librairie nous permet de récupérer des données via HTTPS, ce qui auparavant n'était pas possible depuis notre HC2. Alors vu que nous avons, aujourd'hui, tout le nécessaire pour attaquer notre Netatmo directement depuis notre HC2, pourquoi s'en priver Les données recueillies par votre Netatmo sont mis à diposition via des API que vous pouvez interroger quand bon vous semble à la seul condition d'avoir un compte Développeur Netatmo (ne vous inquiéter pas, vous n'aurez pas beson de développer, ni de répondre à des questions étranges). Pour vous inscrire, c'est donc ici : https://auth.netatmo.com/fr-FR/access/signup Suite à votre enregistrement, vous allez obtenir : un id (exemple : 45b1931d19665803515b571c) un code secret (exemple : lyRkJXZLIM8xShACtmQjsCQV4U3djL08Zq1hUStbUJ4) Ces informations + votre login et mot de passe vont permettre d'accéder à vos informations. Voici donc le script nécessaire, à vous de l'importer dans une nouvelle scène et de modifier les 4 premières lignes. local n_client_id = "45b1931d19665803515b571c" local n_client_secret = "lyRkJXZLIM8xShACtmQjsCQV4U3djL08Zq1hUStbUJ4" local n_username = "______________@_____.com" local n_password = "password" local hc2_module_virtuel = 139 -- le module virtuel "Pluie" local debug = true -- affiche ou non les message dans la console local long_lat_adjust = 0.1 -- ajustement de la distance pour trouvé un pluviomètre local version = 2.0 -- ------------------------------------------------------------------------ -- NE PAS TOUCHER -- ------------------------------------------------------------------------ local force_use_rain_public = false local loc = api.get("/settings/location") local lat_ne = loc.latitude + long_lat_adjust local lon_ne = loc.longitude + long_lat_adjust local lat_sw = loc.latitude - long_lat_adjust local lon_sw = loc.longitude - long_lat_adjust local token = "" local int_id = "" local ext_id = "" local ext_bat = 0 local rain_id = "" local rain_bat = 0 local temperature_interieure = -1000 local temperature_exterieure = -1000 local co2 = -1000 local humidite_interne = -1000 local humidite_externe = -1000 local pression = -1000 local bruit = -1000 local rains = {hour = -1000, day = -1000, week = -1000, month = -1000} -- ------------------------------------------------------------------------ -- Exécuté après chaque requète HTTP -- ------------------------------------------------------------------------ function afterHttpRequest() if (temperature_interieure > -1000) then end if (temperature_exterieure > -1000) then end if (co2 > -1000) then end if (humidite_interne > -1000) then end if (humidite_externe > -1000) then end if (pression > -1000) then end if (bruit > -1000) then end if (rains["hour"] > -1000) then if (rains["hour"] == -1) then fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblHeure.value", "n/a") else fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblHeure.value", " "..rains["hour"]) end end if (rains["day"] > -1000) then if (rains["day"] == -1) then fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblJour.value", "n/a") else fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblJour.value", " "..rains["day"]) end end if (rains["week"] > -1000) then if (rains["week"] == -1) then fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblSemaine.value", "n/a") else fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblSemaine.value", " "..rains["week"]) end end if (rains["month"] > -1000) then if (rains["month"] == -1) then fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblMois.value", "n/a") else fibaro:call(hc2_module_virtuel, "setProperty", "ui.lblMois.value", " "..rains["month"]) end end end -- ------------------------------------------------------------------------ -- Affichage dans la console -- ------------------------------------------------------------------------ function log(message, force) force = force or false if (debug or force) then print(__convertToString(message)) end end -- ------------------------------------------------------------------------ -- Retourne le niveau de batterie en pourcent -- ------------------------------------------------------------------------ function calcBat(bat, ext) local max = 6000 local min = 4200 if (ext) then max = 6000 min = 3600 end if (bat > max) then bat = max end return math.floor(bat * 100 / max) end -- ------------------------------------------------------------------------ -- Arrondi -- ------------------------------------------------------------------------ local function roundToNthDecimal(num, n) local mult = 10^(n or 0) return math.floor(num * mult + 0.5) / mult end -- ------------------------------------------------------------------------ -- Interrogation de l'API -- ------------------------------------------------------------------------ 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)) afterHttpRequest() end, error = function(response) log(" ERROR !!! " .. url, true) end, }) end -- ------------------------------------------------------------------------ -- Mesures de l'unité interne -- ------------------------------------------------------------------------ function getMesuresInt() getResponseData("https://api.netatmo.net/api/getmeasure","access_token="..token.."&device_id="..int_id.."&scale=max&type=Temperature,CO2,Humidity,Pressure,Noise&date_end=last", function(data) log("----------========== Module intérieur ==========----------") temperature_interieure = data.body[1].value[1][1] co2 = data.body[1].value[1][2] humidite_interne = data.body[1].value[1][3] pression = data.body[1].value[1][4] bruit = data.body[1].value[1][5] log("temperature_interieure = " .. temperature_interieure) log("co2 = " .. co2) log("humidite_interne = " .. humidite_interne) log("pression = " .. pression) log("bruit = " .. bruit) end ) end -- ------------------------------------------------------------------------ -- Mesure de l'unité externe -- ------------------------------------------------------------------------ function getMesuresExt() getResponseData("https://api.netatmo.net/api/getmeasure","access_token="..token.."&device_id="..int_id.."&module_id="..ext_id.."&scale=max&type=Temperature,Humidity&date_end=last", function(data) log("----------========== Module extérieur ==========----------") temperature_exterieure = data.body[1].value[1][1] humidite_externe = data.body[1].value[1][2] log("temperature_exterieure = " .. temperature_exterieure) log("humidite_externe = " .. humidite_externe) end ) end -- ------------------------------------------------------------------------ -- Obtention des informations sur un pluviomètre proche -- ------------------------------------------------------------------------ function getRainNear() getResponseData("https://api.netatmo.net/api/getpublicdata","access_token="..token .. "&lat_ne="..lat_ne.."&lon_ne="..lon_ne.."&lat_sw="..lat_sw.."&lon_sw="..lon_sw, function(data) --log(data) rains["week"] = -1 rains["month"] = -1 rains["hour"] = -1 rains["day"] = -1 log("----------========== D e v i c e s =========----------") for _, v in pairs(data.body) do for l, w in pairs(v.measures) do if (type(w.rain_24h) ~= "nil") then rains["day"] = w.rain_24h rains["hour"] = w.rain_60min end end end if (rains["day"] == -1000) then log("Impossible de trouver un pluviomètre à proximité, augmentez [long_lat_adjust]", true) else log("Pluie jour : " .. rains["day"]) log("Pluie heure : " .. rains["hour"]) end end ) end -- ------------------------------------------------------------------------ -- Mesure du détecteur de pluie historique -- ------------------------------------------------------------------------ function getMesuresRain(duree, variable) local now = os.time(); getResponseData("https://api.netatmo.net/api/getmeasure","access_token="..token.."&device_id="..int_id.."&module_id="..rain_id.."&scale=1hour&type=sum_rain&real_time=true&date_begin="..os.date("!%c", (now - duree)), function(data) log("----------========== Pluie histo ==========----------") local cumul = 0 for k, v in pairs(data.body) do for l, w in pairs(v.value) do cumul = cumul + w[1] end end cumul = roundToNthDecimal(cumul, 2) rains[variable] = cumul log("rain["..variable.."] = " .. rains[variable]) end ) end -- ------------------------------------------------------------------------ -- Obtention des informations sur les devices -- ------------------------------------------------------------------------ function getDevices() getResponseData("https://api.netatmo.net/api/devicelist","access_token="..token, function(data) log("----------========== D e v i c e s =========----------") for _, v in pairs(data.body.modules) do if (v.data_type[1] == "Rain") then rain_id = v._id rain_bat = calcBat(v.battery_vp, true) else ext_id = v._id ext_bat = calcBat(v.battery_vp, true) end end int_id = data.body.devices[1]._id getMesuresInt() getMesuresExt() if (rain_id ~= "" and not force_use_rain_public) then getMesuresRain(60 * 60, "hour") getMesuresRain(60 * 60 * 24, "day") getMesuresRain(60 * 60 * 24 * 7, "week") getMesuresRain(60 * 60 * 24 * 30, "month") else getRainNear() end end ) end -- ------------------------------------------------------------------------ -- Authentification -- ------------------------------------------------------------------------ function auth(nextFunction) local request_body = "grant_type=password&client_id=" .. n_client_id .. "&client_secret=" .. n_client_secret .. "&username=" .. n_username .. "&password=" .. n_password .. "&scope=read_station" getResponseData("https://api.netatmo.net/oauth2/token", request_body, function(data) token = data.access_token log(token) nextFunction() end ) end auth(getDevices) log("Last request : " .. os.date("%x - %X"), true) si vous avez l'âme d'un développeur ou d'un aventurier, la méthode à modifier est afterHttpRequest() sinon, rendez-vous au post suivant. P.S. Merci à @PITP2 pour son support. Edit : nouvelle version du script. Si ce dernier détecte que vous n'avez pas de pluviomètre, il va rechercher un pluviomètre à proximité de chez vous (uniquement les relevés de la dernière heure et jour). La distance de recherche peux être adaptée en ajustant la variable long_lat_adjust (0.1 par défaut). Il s'agit du cercle de recherche en latitude/longitude autour de chez vous.
  14. labomatik

    Plex - Films En Cours De Lecture

    Bonjour à tous, Ma petite contribution pour pouvoir récupérer les films en cours de lecture sur le serveur Plex. Il y a encore beaucoup d'amélioration possible mais il modifie déjà une variable globale (1 = film en cours, 0 = aucun film) et affiche le film en cours. Note: Aucune gestion de la lecture de plusieurs films en même temps. Il manque aussi l'information sur la source du lecteur plex (tv, iphone, ...), ce sera pour une prochaine version ;-) Importez le virtual device PlexHC2.vfib.zip PlexHC2 modifiez ces lignes: -- !!! VOS PARAMETRES !!! PlexHC2.Plex_ip = '192.168.1.9' -- IP du serveur Plex PlexHC2.Plex_port = 32400 -- PlexHC2.globalvariable = "" L'image du VD Note2: Largement inspiré du script de Steven MétéoAlerte (un grand merci à lui pour son travail)
  15. Bonjour, Sur le post du script pour le contrôle du niveau des piles j'ai abordé le sujet nÅ“uds morts pour les détecter et voici un script tip top qui/ - Contrôle les nÅ“uds morts, - Chercher a les réveiller, - Envoie des notifications pour avertir --[[ %% autostart %% properties %% globals --]] local sourceTrigger = fibaro:getSourceTrigger(); if (sourceTrigger["type"] == "autostart") then while true do local currentDate = os.date("*t"); local startSource = fibaro:getSourceTrigger(); if ( ( (tonumber(os.date("%H%M")) >= tonumber(string.format("%02d%02d", "07", "00")) and tonumber(os.date("%H%M")) <= tonumber(string.format("%02d%02d", "23", "00"))) and (math.floor(os.time()/60)-math.floor(1369026000/60))%2 == 0 ) ) then local i = 1 local TotalDevices = 156 + 1 while i < TotalDevices do local status = fibaro:getValue(i, 'dead'); if status == "1" then fibaro:setGlobal('lastDeadNode', i); -- fibaro:call(30, "pressButton", "6"); fibaro:call(1, "wakeUpDeadDevice",i); fibaro:debug("Try to wake up node "..i); fibaro:call(68, "sendPush", "Try to wake up node "..i); fibaro:sleep(5*1000); local status = fibaro:getValue(i, 'dead'); if status == "1" then fibaro:debug("Device "..i.." still dead"); fibaro:call(68, "sendPush", "Device "..i.." still dead"); -- fibaro:call(30, "pressButton", "6"); -- fibaro:call(65, "sendDefinedPushNotification", "9"); -- fibaro:call(2, "sendEmail", "DEAD "..i); else -- fibaro:call(30, "pressButton", "7"); fibaro:debug("Device "..i.." fixed"); fibaro:call(68, "sendPush", "Device "..i.." fixed"); end else end i = i + 1 end end fibaro:sleep(60*1000); end else local currentDate = os.date("*t"); local startSource = fibaro:getSourceTrigger(); if ( startSource["type"] == "other" ) then fibaro:debug("send notification"); fibaro:call(68, "sendPush", "start check dead node"); local i = 1 local TotalDevices = 156 + 1 while i < TotalDevices do local status = fibaro:getValue(i, 'dead'); if status == "1" then fibaro:setGlobal('lastDeadNode', i); -- fibaro:call(30, "pressButton", "6"); fibaro:call(1, "wakeUpDeadDevice",i); fibaro:debug("Try to wake up node "..i); fibaro:call(68, "sendPush", "Try to wake up node "..i); fibaro:sleep(5*1000); local status = fibaro:getValue(i, 'dead'); if status == "1" then fibaro:debug("Device "..i.." still dead"); fibaro:call(68, "sendPush", "Device "..i.." still dead"); -- fibaro:call(30, "pressButton", "6"); -- fibaro:call(65, "sendDefinedPushNotification", "9"); -- fibaro:call(2, "sendEmail", "DEAD "..i); else -- fibaro:call(30, "pressButton", "7"); fibaro:debug("Device "..i.." fixed"); fibaro:call(68, "sendPush", "Device "..i.." fixed"); end else end i = i + 1 end end end Voici le script,son auteur est Olivier MALE. Il faut l'adapter pour le N° d'ID pour le push. Son auteur a aussi mis des "--" devant certaines lignes de notifications push et de virtual device, perso j'ai supprimé ces lignes. Le script fonctionne nickel chez moi.
  16. Nikko

    Backup Via Scene Lua

    Bonjour, Voici un résumé sur la réalisation/suppression de backups via des scènes en Lua. La création/suppression de backup s'effectue en temps normal sur l'interface du HomeCenter à la page Diagnostiques/Sauvegarde et restauration. Le code donné dons les 2 scènes n'est pas des plus optimisé; cela constitue juste une base. EDIT (03/12/2016): Mise à jour avec l'api pour les versions >=4.101; voir plus loin: (https://www.domotique-fibaro.fr/topic/8641-backup-via-scene-lua/?do=findComment&comment=146362) Les Commandes de l'API La récupération au format JSON de la liste des backups se fait à l'addresse http://HC2/api/settings/backups Pour Créer un Backup on utilise l'addresse http://HC2/api/settings/backups avec une requète de type en POST avec les paramètres action et description. Pour Supprimer un Backup, on utilise l'addresse http://HC2/api/settings/backups?id=xx (où xx est le numéro de backup). La requète est de type DELETE avec comme paramètre id=xx => Comme les urls de l'api vont être appelées depuis des scènes lua, l'ip de la box utilisée sera 127.0.0.1 (port 11111) => En cas d'appel sur l'ip LAN de la box (Ex: http://192.168.0.100/api/settings/backups) , il faudra en plus transmettre l'authentification dans la requète. Attention: Lors de la création de Backup, "tout le reste" est suspendu; de même après que le backup soit effectué, le moteur Z-Wave et d'autres services redémarrent. Donc en cas de planification , privilégier la nuit, là ou l'activité ZWave, scénarios, est faible/inexistante. Scène de création d'un backup Exemple de Scène de création d'un Backup, avec notification vers portable: --[[ %% properties %% events %% globals --]] -- ID des mobiles,tablettes pour notification local portable = { 385,378 } -- Message Descriptif du Backup local descriptif = 'Backup du '..os.date("%d/%m/%y - %HH%M") function sendPush(message) if #portable > 0 then for _,v in ipairs(portable) do fibaro:call(v,'sendPush', message) end end end local url = 'http://127.0.0.1:11111/api/settings/backups' local httpClient = net.HTTPClient() httpClient:request(url , { success = function(response) if tonumber(response.status) == 201 then print("Backup Created at " .. os.date()) sendPush(descriptif .. ' effectué') else print("Error " .. response.status) sendPush('Erreur lors de la création du Backup') end end, error = function(err) print('error = ' .. err) end, options = { method = 'POST', headers = { ["content-type"] = 'application/x-www-form-urlencoded;' }, data = 'action=create&description='..descriptif } }); Depuis la page des backups, on peut vérifier que la scène fonctionne: Pour les utilisateurs de GEA, on peut déclencher cette sauvegarde le 1er samedi de chaque mois par exemple: -- Fonction déterminant si nous sommes le 1er samedi du mois function isFirstSaturday() local t = os.date('*t') return ( t['day'] < 8 and t['wday'] == 7 ) end -- Backup le 1er samedi du mois GEA.add({"Function",function() return isFirstSaturday() end} , 30 , "Backup Mensuel du HC2" , {{"Time","01:00","01:01"},{"Scenario", 12}}) . Scène de suppression d'un backup Exemple de Scene Lua pour réaliser la suppression du backup le plus ancien: --[[ %% properties %% events %% globals --]] -- Flag dryrun; Si true, la requete sur api pour effacer le backup n'est pas effectuée local dryrun = true -- Récupération de la list des backups local backups = api.get('/settings/backups') -- Vérification de présence Backup if (backups and type(backups == 'table') and #backups > 0) then if #backups > 1 then print(#backups .. ' Backups présents') else print('1 Backup présent') end for i in ipairs(backups) do fibaro:debug('ID: '..backups[i]['id']..' | TIMESTAMP: '..backups[i]['timestamp']..' | DESCRIPTION: '..backups[i]['description']) end else print('Pas de backup ou erreur lors de la récupération de la liste') fibaro:abort() end -- Pour chaque Backup on stock le timestamp de la date de réalisation dans une table -- On classe ensuite les timestamps par ordre croissant local timestamp = {} for i in ipairs(backups) do table.insert(timestamp, backups[i]['timestamp']) end table.sort(timestamp) -- Le 1er timestamp de la table est le plus petit donc le plus ancien en epochtime -- Dans la table de backup on recherche le backup ayant ce timestamp local id = false for i in ipairs(backups) do if (tonumber(backups[i]['timestamp']) == tonumber(timestamp[1])) then id = backups[i]['id'] end end if id then print("ID du backup le plus ancien: "..id) else print("Erreur lors de la récupération de l'ID") fibaro:abort() end -- Requete via API pour effacer le backup le plus ancien if not dryrun then local url = 'http://127.0.0.1:11111/api/settings/backups?id='..id local httpClient = net.HTTPClient() httpClient:request(url , { success = function(response) if tonumber(response.status) == 200 then print("Backup deleted at " .. os.date()) else print("Error " .. response.status) end end, error = function(err) print('error = ' .. err) end, options = { method = 'DELETE', headers = { ["content-type"] = 'application/x-www-form-urlencoded;' }, data = 'id='..id } }); end . Cette Scène produit le debug suivant: Nicolas
  17. Après avoir rencontré quelques difficultés avec la portée des variables, je vous propose un précis sur le sujet : Petit rappel : Une variable permet de stocker des valeurs de façon temporaire ou non dans des noms. On pourra en suite faire appel àces noms n'importe où dans notre code. Si cette gestion de l'information semble suffisante dans un petit script, il n'en va pas de même pour de longs codes (comme ceux dont nous gratifient Krikroff ou Steven) En effet, il serait catastrophique que des fonctions différentes utilisent le même nom de variable pour y stocker des valeurs !!! Les variables seraient alors écrasées ... Et ça c'est pas bon... La solution est de limiter la portée d'une variable en utilisant la notion de variable locale. Ainsi la variable locale n'aura d'existence que dans le bloc dans laquelle elle a été crée ! Mais qu'est-ce qu'un bloc ? Et bien c'est par exemple ce qui est situé entre if et end, ou entre do et end, ou encore une fonction ... Ben alors comment qu'on va faire maintenant ? Déjà, on a de la chance, puisque le Lua utilise ces 2 types de variables et que c'est super simple de les créer ! Les variables Globales sont crées simplement en tapant leur nom suivi d'un "=" et de la valeur numérique souhaitée ou du texte entre "" ou ' ' : MaVariableGlobale = 1 Attention : Fibaro propose en plus une gestion particulière des variables Globales par le biais de son Panneau variables. Il sera donc inutile de la déclarer ànouveau dans votre code pour l'utiliser. Cette gestion permet d'utiliser une même variable commune àtoutes les scènes ou modules de votre HC2. Les variables Locales sont quant àelles créées en ajoutant cette fois le mot local devant le nom de la variable (c'est ce mot clé qui restreint sa portée àun bloc ou àune fonction) : local MaVariableLocale = 2 Attention : Pour changer la valeur de cette variable locale il ne sera plus nécessaire de mettre le mot clé "local" devant ! Bon après ça dépend de ce que vous souhaitez faire... Mettre àjour la variable ou en créer une nouvelle (voir plus bas *) Mais c'est peut-être ce que vous voulez finalement ? Oui et non Il faudra être vigilant quant àla portée que l'on souhaite donnée àsa variable et choisir qu'elle soit locale ou globale. En effet, dans une fonction, il peut être intéressant d'utiliser une variable et d'être certain qu'il n'y aura pas de conflit avec un nom que vous auriez utilisé avant. C'est làque vous allez utiliser la puissance de la variable LOCALE ! Voici un exemple de la portée d'une variable locale (regardez la valeur retournée par le début). On voit clairement que nous avons àfaire à2 variables locales : local MaVarLocale = 1 fibaro:debug(MaVarLocale) -- donne 1 do local MaVarLocale = 5 -- création d'une nouvelle variable locale au sein du bloc (rien àvoir avec celle créée ligne 2 !) fibaro:debug(MaVarLocale) -- donne 5 end fibaro:debug(MaVarLocale) -- donne 1 Même si elles ont le même nom, elles ont été déclarées dans 2 blocs différents. Le système les considère comme complètement différentes àcause du mot clé local. Le danger avec le Lua c'est que ce langage est très permissif et qu'àforce d'omission, on peut se prendre les pieds sans le tapis ... Je m'explique en reprenant le même code qu'au dessus en supprimant le mot clé local : MaVariable = 1 -- création d'une variable globale fibaro:debug(MaVariable) -- donne 1 do MaVariable = 5 -- mise àjour de la variable globale créée ligne 2 fibaro:debug(MaVariable) -- donne 5 end fibaro:debug(MaVariable) -- donne 5 Ici nous n'avons àfaire qu'àune seule variable globale (elle s'appelle MaVariable ! Elle est considérée ici par le système comme globale car nous ne l'avons jamais déclarée avec le mot clé local. Ok ! Alors maintenant vous vous dites : je vais déclarer ma variable MaVariable en local dès la première ligne (comme ça je suis tranquille) : local MaVariable = 1 -- création d'une variable locale fibaro:debug(MaVariable) -- donne 1 do MaVariable = 5 -- ici pas de mot clé local, donc mise àjour de la variable déclarée ligne 2 fibaro:debug(MaVariable) -- donne 5 end fibaro:debug(MaVariable) -- donne 5 (C'est ici plus bas * !!!) Ici il n'y a pas d'erreur ! Ce code est valable si vous souhaitiez vraiment utiliser la même variable locale (dans un nouveau bloc) que celle déclarée en locale au début de votre script (et donc la mettre àjour). La Variable est mise àjour et non créer au sein du nouveau bloc. Le code suivant crée 4 variables locales MaVariable : local MaVariable = 0 -- création d'une variable locale do local MaVariable = 1 -- création d'une nouvelle variable locale (rien àvoir avec le ligne 2 end do local MaVariable = 2 -- création d'une nouvelle variable locale (rien àvoir avec le ligne 2 et 5 end do local MaVariable = 3 -- création d'une nouvelle variable locale (rien àvoir avec le ligne 2 ; 5 et 9) end Le code suivant crée 1 seule variable locale MaVariable et la met àjour 3 fois : local MaVariable = 0 -- création de la variable locale do MaVariable = 1 -- mise àjour de la variable déclarée ligne 2 end do MaVariable = 2 -- mise àjour de la variable déclarée ligne 2 et modifiée àla ligne 5 end do MaVariable = 3 -- mise àjour de la variable déclarée ligne 2, modifiée àla ligne 5 et modifiée ànouveau ligne 9 end Ce code utilise une seule variable Globale MaVariable car on a supprimé la 1ère ligne ! : -- On supprime la déclaration de la variable locale en la commentant : -- local MaVariable = 0 do MaVariable = 1 -- création de la variable globale ! end do MaVariable = 2 -- mise àjour de la variable globale ! end do MaVariable = 3 -- mise àjour de la variable globale ! end Subtile non ?! Une ligne en moins au début et on passe tout de local en globale ! Voilàpourquoi je disais que le côté permissif du Lua peut jouer des tours. Imaginez que vous vous trouviez àla tête de 1500 lignes de codes, il se pourrait que vous souhaitiez mettre àjour une variable globale (donc sans local devant) mais que malheureusement vous ayez àfaire àune variable locale déclarée quelques lignes au-dessus... ... En espérant que ce sujet vous ait été utile.
  18. sebcbien

    Detection De Présence

    Bonjour, Suite à une conversation en MP avec un de nos admin chéri ;-), voici ma solution pour détecter la présence via smartphone. L'idée est de savoir quand ma femme ou moi même sommes à la maison afin de pouvoir lancer des scénarios ou en bloquer l’exécution. J'ai fait ça il y a longtemps, et bien sur je n'ai pas tout fait tout seul. Je me souviens avoir fait quelques modifications pour que ça tourne comme je le voulais, mais je ne sais plus lesquelles. Bref, voici le package complet, pour certains scripts, comme pour le ping par exemple la base est de Krikroff et j'ai laissé le copyright. J'ai mis le Virtual Device en attach et le code du bouton ci-dessous . IP Smartphone Presence Check V1.0.vfib !!! voir post plus loin dans le fil pour les V1.1 V1.2 V1.3 V2.0 et suivantes !!! V2.1 ici: https://www.domotique-fibaro.fr/topic/2613-detection-de-prã©sence/?do=findComment&comment=121355 V1.3 ici: http://www.domotique-fibaro.fr/index.php/topic/2613-detection-de-pr%C3%A9sence/page-3#entry35219 - il faut créer une variable globale (non prédéfinie) par device à surveiller (moi j'utilise "Phone_GG_Present" pour le tel de ma femme) et la déclarer en début de script du bouton. - il faut encoder l'adresse IP du téléphone dans les paramètres du Virtual device (pensez à déterminer une ip Wifi fixe pour votre smartphone) - il faut encoder le port ouvert sur votre téléphone dans les paramètres du Virtual device (3500 ou 3401) - Sur Androà¯d, il n'y a pas de port ouvert par défaut pour accepter le ping, le moyen le plus simple est d'installer l'application Sonos et a lancer, c'est tout (pas besoin d'avoir du matos sonos pour que ça fonctionne) - Sur iPhone idem, mais je n'ai pas testé personellement - si vous ne voulez pas utiliser le mainloop comme "scheduler" , créez simplement une scène qui va cliquer sur le bouton de demande de présence toutes les minutes... ou avec l'excellent GEA, avec la ligne ci-dessous (à adapter): -- Mise à jour des Présences par détection d'adresses IP toutes les minutes GEA.add(true , 1*60, "",{{"VirtualDevice", id["VD_PRESENCE_SEB"], "1"},{"VirtualDevice", id["VD_PRESENCE_GG"], "1"},{"Repeat"}}) Notification de présence en utilisant GEA, entre 8h et 21h: N'oubliez pas de mettre les VG dans l'entête. Ces exemple sont repris dans le post GEA de ma signature --------------DETECTION PRESENCE-------------- -- Signale GG at Home GEA peux se déclencher sur un changement de valeur d'une variable global GEA.add({"Global", "Phone_GG_Present", "1"}, -1, "Presence GG est maintenant à #value#", {{"Portable", 53}, {"Time", "08:00", "21:00"}}) GEA.add({"Global", "Phone_GG_Present", "0"}, -1, "Presence GG est maintenant à #value#", {{"Portable", 53}, {"Time", "08:00", "21:00"}}) Code bouton VD détect presence V1.0 (ancien code): -- IP Smartphone Presence Check V1.0 -- Copyright © 2014 Sébastien Jauquet. -- http://www.domotique-fibaro.fr/index.php/topic/2613-detection-de-pr%C3%A9sence/ --Using code from: -- Ping v 1.0.1 [05-2013] -- Copyright © 2013 Jean-christophe Vermandé -- http://www.domotique-fibaro.fr/index.php/topic/109-ping-dun-%C3%A9quipement-r%C3%A9seau/page-2 fibaro:log("Starting process"); local _deviceIp = "192.168.10.112"; local variable_globale_phone = "Phone_GG_Present"; local _devicePort = 3500; local _maxRetryProcess = 20; local time = tonumber(os.time()); local maxtime = 56; -- fibaro:setGlobal("Lock_Away","Unlocked") function SecondsToClock(sSeconds) local nSeconds = tonumber(sSeconds) if nSeconds == 0 then return "00:00:00"; else nHours = string.format("%02.f", math.floor(nSeconds/3600)); nMins = string.format("%02.f", math.floor(nSeconds/60 - (nHours*60))); nSecs = string.format("%02.f", math.floor(nSeconds - nHours*3600 - nMins *60)); return nHours..":"..nMins..":"..nSecs end end -- recursive function to ping device local function _ping(retry) retry = retry or 0; -- notify state local elapsed = os.difftime(os.time(), tonumber(time)); local msg = "Loop #".. retry .." since "..SecondsToClock(elapsed); fibaro:log(msg); -- check for no more than 30 seconds if elapsed > maxtime then return false; end --open the socket local tcpSocket = Net.FTcpSocket(_deviceIp, _devicePort); --set the read timeout tcpSocket:setReadTimeout(250); --send packet local bytes, errorCode = tcpSocket:write("test"); --check for error if errorCode == 0 then return true; else if retry < _maxRetryProcess then --fibaro:log("Retry process, please wait..."); fibaro:sleep(1*750); return _ping(retry + 1); end return false; end end --ping device, secure with pcall to catch errors. local f, result = pcall(_ping); local Lock_Away = fibaro:getGlobal("Lock_Away") if (f) then if (result == true) and (Lock_Away == "Unlocked") then fibaro:log("Device has been found."); fibaro:setGlobal(variable_globale_phone,"1") -- fibaro:setGlobal("Present_Phones",os.time()) else fibaro:log("Device was not found!"); fibaro:setGlobal(variable_globale_phone,"0") end else fibaro:log("Error: " .. f); end Code main loop du VD local thismodule = fibaro:getSelfId(); local status = fibaro:getGlobal("Phone_GG_Present") -- fibaro:debug(thismodule); if status == "0" then fibaro:call(thismodule, "setProperty", "currentIcon", 1037) end if status == "1" then fibaro:call(thismodule, "setProperty", "currentIcon", 1036) end fibaro:sleep(1000); Ce n'est certainement pas le code le plus "léché" mais je pense que ça en aidera quand même certains... et puis c'est "tout fait" ;-) Le script va détecter quasi instantanément lorsque le smartphone apparaît sur le réseau, mais pourra mettra jusqu'à une minute pour valider son absence Enjoy !
  19. Bonjour, Le but de ce tuto sera de faire une passerelle pour les données de la netatmo vers emoncms. J'en ai profité pour améliorer le script php classique d'interface entre la netatmo et la HC2 les versions disponibles ot du mal à gérer les installations netatmo avec plusieurs modules. Ici j'ai cherché à améliorer les choses et ça fonctionne même lorsque l'on a plusieurs master device et plusieurs stations additionnelles. En effet, savoir l'ordre des modules renvoyé par netatmo dans ces conditions est un peur hard. J'ai ajouté plusieures pages de résultats au script PHP: une avec un json viewer intégré et un qui retourne le json complet. J'ai aussi optimisé pour minimiser le nombre de requêtes faites à netatmo, histoire de ne pas se faire "jeter" voici déjà la présentation de la plateforme emon CMS très puissante que j'utilise depuis plus d'un an: http://emoncms.org/site/home http://emoncms.org/site/docs/visualisations Personellement je l'utilise pour remonter mes graphiques de valeurs diverses de ma HC2 - températures - consommations eau, gaz, elec - paramètres de ma VMC (T° Vitesse, rendement etc.) J'ai partagé mon script avec un ami et comme il était enchanté, je fais l'effort de le mettre ici aussi ;-) En effet, il suffit de configurer les variables dans le VD, créer un répertoire /netatmo dans www ou web ou html, y mettre le PHP et le répertoire jsoneditor et c'est parti, les données seront remontées automatiquement à emonCMS ! Voici déjà le script côté HC2: Je l'ai mis derrière un bouton, car dans un main loop, une corruption json quelquepart et c'est tout qui plante. Ce bouton dont être cliqué via GEA ou autre scheduler toutes les 10 minutes. Voici le Virtual Device tout fait: Grosse mise à jour à ce post: http://www.domotique-fibaro.fr/index.php/topic/3929-yagda-yet-another-graphic-data-analyser-netatmo-vmc-emoncms-json-viewer/#entry63238 Netatmo_V2.vfib Attention, dans ce post ne figure que les scripts de la première version, voir plus loin dans le fil pour les versions suivantes ! ----------------------------------------------------------------------------------------- -- YAGDA - yet another graphic data analyser V2.01 -- Retreive Netatmo values for more than 2 modules, compute CO2 and push to EmonCMS -- Sebastien Jauquet -- Février 2015 -- Thanks to cedriclocqueneux, krikroff, i-magin and all contibutors to the netatmo code ----------------------------------------------------------------------------------------- -- Instructions: -- Create an free emoncms.org account -- Retrieve your Write API Key from it -- Create a Global variable (undefined) -> CO2_Max_Value to store the max value of CO2 of the house - if you dont need this, set CO2 to false (default: 0) -- Install my netatmo.php in your webserver and write his address in the ip Address of this module -- for each value you want to be pushed to emoncms, modify the section -- Push To EMONCMS -- below -- Create a block scene or use gea to click this button each 10 minutes (to avoid rejection from the api of Netatmo) local EmonCMS_Prefix = "NETATMO_" -- prefix of the id of the inpus to be created in emoncms (convenient for testing to not alter current feeds) local PushToEmonCMS = true -- true = push to emoncms - false = do not push local selfId = fibaro:getSelfId(); local thismodule=fibaro:getSelfId() local domaine = fibaro:get(selfId, 'IPAddress') local PushItem local CO2_Max_Value_Local = 0 -- if you dont need this, set CO2 to false (default: 0) local emoncms = Net.FHttp("emoncms.org",80) local emoncms_api_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" -- your EMONCMS WRITE api Key EmonCMS = {}; if (temperature_exterieure==nil) then temperature_exterieure = ""; end if (humidite_exterieure==nil) then humidite_exterieure = ""; end if (temperature_interieure==nil) then temperature_interieure = ""; end if (humidite_interieure==nil) then humidite_interieure = ""; end if (co2==nil) then co2 = ""; end if (pression==nil) then pression = ""; end if (bruit==nil) then bruit = ""; end if (temperature_int_mod2==nil) then temperature_int_mod2 = ""; end if (humidite_int_mod2==nil) then humidite_int_mod2 = ""; end if (co2_mod2==nil) then co2_mod2 = ""; end if (temperature_int_mod3==nil) then temperature_int_mod3 = ""; end if (humidite_int_mod3==nil) then humidite_int_mod3 = ""; end if (co2_mod3==nil) then co2_mod3 = ""; end if (temperature_int_mod4==nil) then temperature_int_mod4 = ""; end if (humidite_int_mod4==nil) then humidite_int_mod4 = ""; end if (co2_mod4==nil) then co2_mod4 = ""; end if(refreshUI==nil) then -- Loads in memory only the first occurence function refreshUI(ext, bruit, titre, tempmod, co2mod, humidmod, lastupdate, laststatus) fibaro:call(selfId,"setProperty","ui.ext.value",ext); fibaro:call(selfId,"setProperty","ui.bruit.value",bruit); fibaro:call(selfId,"setProperty","ui.titre.value",titre); fibaro:call(selfId,"setProperty","ui.tempmod.value",tempmod); fibaro:call(selfId,"setProperty","ui.co2mod.value",co2mod); fibaro:call(selfId,"setProperty","ui.humidmod.value",humidmod); fibaro:call(selfId,"setProperty","ui.lastupdate.value",lastupdate); fibaro:call(selfId,"setProperty","ui.laststatus.value",laststatus); end; end if(getExt==nil) then -- Loads in memory only the first occurence function getExt(retry) retry = retry or 0 -- Setting up the connection data local FHTE = Net.FHttp(domaine, 80); -- Netatmo extérieur local response = FHTE:GET("/netatmo/netatmo.php?parameter=ext"); -- decoding json string to table if (response~= nil) then local result = nil; result = json.decode(response); if (result ~= nil) then -- prevent: attempt to index field 'body' (a nil value) if (result.body ~= nil) then temperature_exterieure = result.body[1].value[1][1] or "n.c"; humidite_exterieure =result.body[1].value[1][2] or "n.c"; -- variable globale pour info sms local msg = "Température extérieure : "..temperature_exterieure.."°C"; fibaro:setGlobal("tempext", msg); return true; else fibaro:debug("Netatmo EXT: erreur le " .. os.date()); if (result.error ~= nil) then fibaro:debug("error code: "..result.error.code..", message: "..result.error.message); end end else fibaro:debug("Netatmo EXT: erreur decodage json le " .. os.date()); end else fibaro:debug("Netatmo EXT:la reponse est null !"); end if ((retry or 5)< 5) then fibaro:debug("Retry #"..retry.."process, please wait..."); fibaro:sleep(5000); return getInt(tonumber(retry+1)); else return false; end end; end if(getInt==nil) then -- Loads in memory only the first occurence function getInt(retry) retry = retry or 0; -- Setting up the connection data local FHTE = Net.FHttp(domaine, 80); -- Netatmo intérieur local response = FHTE:GET("/netatmo/netatmo.php?parameter=int"); -- decoding json string to table if (response~= nil) then local result = nil; result = json.decode(response); if (result ~= nil) then -- prevent: attempt to index field 'body' (a nil value) if (result.body ~= nil) then temperature_interieure = result.body[1].value[1][1] or "n.c"; humidite_interieure = result.body[1].value[1][3] or "n.c"; co2 = result.body[1].value[1][2] or "n.c"; pression = result.body[1].value[1][4] or "n.c"; bruit = result.body[1].value[1][5] or "n.c"; -- variable globale pour info sms fibaro:setGlobal("tempint", "Température intérieure : "..temperature_interieure.."°C"); return true; else fibaro:debug("Netatmo INT: erreur le " .. os.date()); if (result.error ~= nil) then fibaro:debug("error code: "..result.error.code..", message: "..result.error.message); end end else fibaro:debug("Netatmo INT: erreur decodage json le " .. os.date()); end else fibaro:debug("Netatmo INT:la reponse est null !"); end if ((retry or 5)< 5) then fibaro:debug("Retry #"..retry.."process, please wait..."); fibaro:sleep(5000); return getExt(tonumber(retry+1)); else return false; end end; end if(getMod2==nil) then -- Loads in memory only the first occurence function getMod2(retry) retry = retry or 0; -- Setting up the connection data local FHTE = Net.FHttp(domaine, 80); -- Netatmo intérieur local response = FHTE:GET("/netatmo/netatmo.php?parameter=mod2"); -- decoding json string to table if (response~= nil) then local result = nil; result = json.decode(response); if (result ~= nil) then -- prevent: attempt to index field 'body' (a nil value) if (result.body ~= nil) then temperature_int_mod2 = result.body[1].value[1][1] or "n.c"; humidite_int_mod2 = result.body[1].value[1][2] or "n.c"; co2_mod2 = result.body[1].value[1][3] or "n.c"; -- variable globale pour info sms -- fibaro:setGlobal("tempint", "Température intérieure : "..temperature_interieure.."°C"); return true; else fibaro:debug("Netatmo INT_mod2: erreur le " .. os.date()); if (result.error ~= nil) then fibaro:debug("error code: "..result.error.code..", message: "..result.error.message); end end else fibaro:debug("Netatmo INT_mod2: erreur decodage json le " .. os.date()); end else fibaro:debug("Netatmo INT_mod2:la reponse est null !"); end if ((retry or 5)< 5) then fibaro:debug("Retry #"..retry.."process, please wait..."); fibaro:sleep(5000); return getExt(tonumber(retry+1)); else return false; end end; end if(getMod3==nil) then -- Loads in memory only the first occurence function getMod3(retry) retry = retry or 0; -- Setting up the connection data local FHTE = Net.FHttp(domaine, 80); -- Netatmo intérieur local response = FHTE:GET("/netatmo/netatmo.php?parameter=mod3"); -- decoding json string to table if (response~= nil) then local result = nil; result = json.decode(response); if (result ~= nil) then -- prevent: attempt to index field 'body' (a nil value) if (result.body ~= nil) then temperature_int_mod3 = result.body[1].value[1][1] or "n.c"; humidite_int_mod3 = result.body[1].value[1][2] or "n.c"; co2_mod3 = result.body[1].value[1][3] or "n.c"; -- variable globale pour info sms -- fibaro:setGlobal("tempint", "Température intérieure : "..temperature_interieure.."°C"); return true; else fibaro:debug("Netatmo INT_mod3: erreur le " .. os.date()); if (result.error ~= nil) then fibaro:debug("error code: "..result.error.code..", message: "..result.error.message); end end else fibaro:debug("Netatmo INT_mod3: erreur decodage json le " .. os.date()); end else fibaro:debug("Netatmo INT_mod3:la reponse est null !"); end if ((retry or 5)< 5) then fibaro:debug("Retry #"..retry.."process, please wait..."); fibaro:sleep(5000); return getExt(tonumber(retry+1)); else return false; end end; end if(getMod4==nil) then -- Loads in memory only the first occurence function getMod4(retry) retry = retry or 0; -- Setting up the connection data local FHTE = Net.FHttp(domaine, 80); -- Netatmo intérieur local response = FHTE:GET("/netatmo/netatmo.php?parameter=mod4"); -- decoding json string to table if (response~= nil) then local result = nil; result = json.decode(response); if (result ~= nil) then -- prevent: attempt to index field 'body' (a nil value) if (result.body ~= nil) then temperature_int_mod4 = result.body[1].value[1][1] or "n.c"; humidite_int_mod4 = result.body[1].value[1][2] or "n.c"; co2_mod4 = result.body[1].value[1][3] or "n.c"; -- variable globale pour info sms -- fibaro:setGlobal("tempint", "Température intérieure : "..temperature_interieure.."°C"); return true; else fibaro:debug("Netatmo INT_mod4: erreur le " .. os.date()); if (result.error ~= nil) then fibaro:debug("error code: "..result.error.code..", message: "..result.error.message); end end else fibaro:debug("Netatmo INT_mod4: erreur decodage json le " .. os.date()); end else fibaro:debug("Netatmo INT_mod4:la reponse est null !"); end if ((retry or 5)< 5) then fibaro:debug("Retry #"..retry.."process, please wait..."); fibaro:sleep(5000); return getExt(tonumber(retry+1)); else return false; end end; end function EmonCMS:Push(payloademon) payloademon = "/input/post.json?json={" .. EmonCMS_Prefix .. payloademon .. "}&apikey=" .. emoncms_api_key response, status, errorCode = emoncms:GET(payloademon); fibaro:debug("Payload: " .. payloademon) ; fibaro:debug("response: " .. response .. " Status: " .. status .. " errorcode: " .. errorCode) ; fibaro:sleep(500); end local function main() -- retrieve values from netatmo.php local resInt, resExt, resMod2, resMod3, resMod4 = false, false, false, false, false; local status, err = pcall(function () resInt = getInt(); end); fibaro:debug("Récupération des données intérieures: " .. tostring(resInt)); if (status == false) then fibaro:debug("err: "..tostring(err or 'n.c')); end local status, err = pcall(function () resExt = getExt(); end); fibaro:debug("Récupération des données extérieures : " .. tostring(resExt)); if (status == false) then fibaro:debug("err: "..tostring(err or 'n.c')); end local status, err = pcall(function () resMod2 = getMod2(); end); fibaro:debug("Récupération des données intérieures Mod2: " .. tostring(resMod2)); if (status == false) then fibaro:debug("err: "..tostring(err or 'n.c')); end local status, err = pcall(function () resMod3 = getMod3(); end); fibaro:debug("Récupération des données intérieures Mod3: " .. tostring(resMod3)); if (status == false) then fibaro:debug("err: "..tostring(err or 'n.c')); end local status, err = pcall(function () resMod4 = getMod4(); end); fibaro:debug("Récupération des données intérieures Mod4: " .. tostring(resMod4)); if (status == false) then fibaro:debug("err: "..tostring(err or 'n.c')); end refreshUI( "Ext: "..temperature_exterieure.." °C - "..humidite_exterieure.." % - "..pression.." mbar", "Bruit Rez: "..bruit.." dB", "Rez - Emilien - Thomas - Parents", temperature_interieure.." - "..temperature_int_mod2.." - "..temperature_int_mod3.." - "..temperature_int_mod4.." °C ", co2.." - "..co2_mod2.." - "..co2_mod3.." - "..co2_mod4.." ppm", humidite_interieure.." - "..humidite_int_mod2.." - "..humidite_int_mod3.." - "..humidite_int_mod4.." % ", os.date("%H:%M"), tostring(resInt).." "..tostring(resExt).." "..tostring(resMod2).." "..tostring(resMod3).." "..tostring(resMod4) ); -- Push To EMONCMS -- if PushToEmonCMS == true then payloademon = "temperature_exterieure:"..temperature_exterieure EmonCMS:Push(payloademon); payloademon = "humidite_exterieure:".. humidite_exterieure EmonCMS:Push(payloademon); payloademon = "pression:".. pression EmonCMS:Push(payloademon); payloademon = "bruit:".. bruit EmonCMS:Push(payloademon); payloademon = "temperature_interieure_Rez:".. temperature_interieure EmonCMS:Push(payloademon); payloademon = "temperature_int_mod2_Emilien:".. temperature_int_mod2 EmonCMS:Push(payloademon); payloademon = "temperature_int_mod3_Thomas:".. temperature_int_mod3 EmonCMS:Push(payloademon); payloademon = "temperature_int_mod4_Parents:".. temperature_int_mod4 EmonCMS:Push(payloademon); payloademon = "humidite_interieure_Rez:".. humidite_interieure EmonCMS:Push(payloademon); payloademon = "humidite_int_mod2_Emilien:".. humidite_int_mod2 EmonCMS:Push(payloademon); payloademon = "humidite_int_mod3_Thomas:".. humidite_int_mod3 EmonCMS:Push(payloademon); payloademon = "humidite_int_mod4_Parents:".. humidite_int_mod4 EmonCMS:Push(payloademon); payloademon = "co2_Rez:".. co2 EmonCMS:Push(payloademon); payloademon = "co2_mod2_Emilien:".. co2_mod2 EmonCMS:Push(payloademon); payloademon = "co2_mod3_Thomas:".. co2_mod3 EmonCMS:Push(payloademon); payloademon = "co2_mod4_Parents:".. co2_mod4 EmonCMS:Push(payloademon); end -- Compute Value MAX CO2 Maison (For VMC Speed VD) if CO2_Max_Value_Local == false then fibaro:debug("not calculating nor storing CO2 Max Value") else CO2_Max_Value_Local = co2 if CO2_Max_Value_Local < co2_mod2 then CO2_Max_Value_Local = co2_mod2 end if CO2_Max_Value_Local < co2_mod3 then CO2_Max_Value_Local = co2_mod3 end if CO2_Max_Value_Local < co2_mod4 then CO2_Max_Value_Local = co2_mod4 end fibaro:setGlobal("CO2_Max_Value", CO2_Max_Value_Local ) fibaro:debug("CO2_Max_Value: ".. CO2_Max_Value_Local ) end end main();
  20. Je voulais partager avec vous la solution que j'ai mis en place pour suivre ma consommation d'eau. Alors j'ai choisi d'un installer un compteur d'eau "Débitmètre avec sortie d'impulsion Compteur d'eau Générateur de débit d'eau 1 Imp./L Qn 1,5m³/h" J'ai connecté l'impulsion sur un détecteur domotique universel FGBS-0001 entre la pin IN2 et GND. Coté HC2, le capteur est vu comme un capteur de présence, dans mon cas j'ai choisi un capteur de porte. Je coche la case qui permet d'exclure ce capteur des alarmes. Je désactive les alarmes (paramètre 13) en mode broadcast disable. Enfin, j'active dans les options avancées du capteur , le mode scène (paramètre 14 positionné sur ON). Je sauvegarde ce paramètre. Ensuite, j'utilise le service ThingSpeak.com pour pouvoir grapher les résultats. Ce service à l'avantage d'être très simple à mettre en place. Il suffit de créé un "Channel" et je nomme le "field1" -> 'Consommation d'eau'. Dans l'onglet "API Keys" du site ThingSpeak, je sauve la valeur de la clé pour le mode écriture ("Write API Key"). Sur le graphique de ce channel, je choisi le mode "SUM 60 minutes en mode ligne" pour avoir un affichage cumulé des consommations sur une période de 1 heure. Je créé un Virtual Device que je nomme "Graph Eau" avec un bouton que je nomme "grapheau". Et J'utilise le code LUA suivant : fibaro:log('Actualisation consommation eau') thingspeak = Net.FHttp('api.thingspeak.com') payload = 'key=VOTREWRITEAPIKEY&field1=1' response, status, errorCode = thingspeak:POST('/update', payload) Je vais dans le menu Scène et je créé une nouvelle scène que je nomme "Graphique Eau", je créé la scène avec le mode utilisant les blocs pour plus de simplicité. Le paramètre 14 du capteur de présence indique que sur l'entrée IN2, un front montant (OFF -> ON) déclenche un code scène 20. Donc j'indique que "SI le capteur du compteur d'eau == "scène activation" 20 alors j’exécute le bouton "grapheau" du virtual device "Graph Eau". Et voilà ! Cela nous donne un graphique heure par heure de la consommation d'eau. Il est à noter que j'ai choisi un compteur qui me donne 1 impulsion par litre rendant l'interprétation des résultats plus facile. J'espère que cela vous sera utile, je trouve la solution assez élégante et facile à mettre en place.
  21. EDIT : VD disponibles dans les pages suivantes Ce tuto est un projet qui démarre, il n'y a encore rien à partager... Mais vu la saison, j'ai la pression. Le but du virtal device est de simplifier la gestion de la piscine, en commençant par la filtration. Pour le moment je débute en LUA et VD et je m'attaque à la logique avant de l'enrober dans un VD ou plugin. La partie logique ne devrait pas trop poser de problème mais l'absence de fonctions partagées sur la HC2 rends les codes peu digeste à priori un peu de théorie: Vous trouverez plein de sites qui traitent de la filtration piscine allant du simple 'température / 2' à des notions plus complexes. Je me base sur la notion de 'durée de cycle' pour régler le temps de marche de la pompe. En effet dans l'absolu le temps n'est pas un bon critère car tout dépend du dimensionnement de la filtration versus le volume de la piscine. Une règle de base répandue sur le net donne Eau > 25 °C : on conseille 3 cycles complets de filtration, au minimum 12 h. 20 °C < eau < 24 °C : compter environ 1 à 2 cycles de filtration soit de 10 à 11 h. 15 °C < eau < 20 °C : 1 cycle complet suffit. 10 °C < eau < 14 °C : ½ voire même ¼ de cycle dans ce cas, ce qui dure approximativement entre 1 et 2 h. Eau < 10 °C : dans ce cas la filtration quotidienne est facultative. Avec un peu de lissage on obtient une courbe température / cycles (donc durée) de la forme Cette courbe n'est pas linéaire mais sans entrer dans les détails elle reste un cas général à adapter à chaque bassin (type désinfection, fréquentation moyenne, environnement....) Je propose de ne pas trop discuter la forme/hauteur de la courbe sur ce forum... De toute façon le VD permettra de fixer votre courbe de référence allant de la simple droite à une forme ultra 'optimisée'. des choix à faire: Vous trouverez de tout comme stratégie pour économiser/optimiser perso je suis plutôt contre la filtration de nuit en HC... - bon et au final + cher filtrer X minutes par heure pour atteindre la durée totale me parait moyen aussi pour mon algo (à créer) je pars sur - 1 à 3 périodes de filtration par jour - filtrer plus en fin de journée pour compenser la fréquentation et assurer un bon nettoyage avant le repos nocturne - j'ai des HC entre 12h et 13h30 autant filtrer (il n'y a pas de petites économies). De plus avoir une filtration fixe vers midi permettra de prendre une température de référence cohérente de jour en jour en plus de la gestion automatique le VD doit permettre de superposer des périodes de 'filtration choc' ; départ immédiat et non-stop pour 12, 24, 48h d'appliquer une correction à la courbe 0 à 400% par exemple pour s'adapter aux périodes de sur-fréquentation ou vent ou.... de proposer un bouton 'baignade' qui permettrait de mettre en marche une heure histoire d’être certain d'avoir la circulation d'eau pour masser le dos :-). de reprendre la planification après un reboot HC2 quelques pistes pour l'affichage dans le VD affichage température de référence utilisée pour le calcul + durée totale de filtration du mode auto affichage température courante affichage état pompe bouton baignade bouton "CHOC +12" + affichage progression choc totale/restante bouton "annuler choc" ajustement 0 à 400% Je vais arrêter la, car c fait déjà pas mal de cas à gérer sans tomber dans une usine à gaz. voila une maquette de VD
  22. jojo

    Images Clé Usb

    Bonjour, Il y a de plus en plus de demandes des fichiers images de la clé recovery de la HC2. Alors j'ai mis cela en public sur mon Google Drive Il contient un un gros fichier ZIP (2,4 GB) "USB RECOVERY HC2" : qui contient une image complète de la clé USB recovery. Complète = la FAT32 et les autres partitions nécessaires. L'image est celle de la 4.056 Le sous-dossier le l'image contient un répertoire /backups avec quelques vieux backups à moi, qui vous seront d'aucune utilité => vous pouvez détruire le contenu de ce répertoire (PAS le répertoire). Voir le tuto de @mprinfo pour son utilisation. Il contient actuellement 4 folders "Recovery Image 3.xxx" : le dossier system qui contient l'image (v3.x) utilisée par le HC2 lors qu'un recovery. Ce dossier se trouve dans la FAT32 de la clé USB "Recovery Image 4.031" : le dossier system qui contient l'image (v4.031) utilisée par le HC2 lors qu'un recovery. Ce dossier se trouve dans la FAT32 de la clé USB "Recovery Image 4.056" : le dossier system qui contient l'image (v4.056) utilisée par le HC2 lors qu'un recovery. Ce dossier se trouve dans la FAT32 de la clé USB "USB RECOVERY HC2" : un gros fichier ZIP (2,4 GB) qui contient une image complète de la clé USB recovery. Complète = la FAT32 et les autres partitions nécessaires. Voir le tuto de mprinfo pour son utilisation. et 1 fichier avec un exemple de doc que je maintiens pour pouvoir repartir de zéro (>60 pages ...)
  23. sebcbien

    Topic Unique S. A. R. A. H.

    Voilà , pas trop de temps pour le moment, mais je vais voir ce que je peux pondre comme tuto pour S.A.R.A.H. Comme je l'ai déjà dit, en général l'installation va toute seule mais parfois ça merde et là 'fo du Barbu costO !... En gros: Windows 10 Installé sur un petit laptop c'est top, pas de place, silencieux, économe en énergie... Télécharger SARAH V4 dans c:/sarah Ajouter le plugin sonos Utiliser mon VD Sarah Say it Pour plus de détails, voir le post suivant. Ancien posts: ------------------- Voici un aperçu Pour la qualité, l'enregistrement n'est pas top mais le volume est au minimum car les enfants dorment Pour la vitesse de conversion en TTS, je pense que ça vous donne une idée... Et l'interruption de la musique est impec et reprends juste après. ----------------- et la photo de mon serveur Jeedom/S.A.R.A.H. Le serveur fermé, c'est beau: Ouvert: Comme vous pouvez le voir c'est un vieux laptop récupéré car l'écran est fichu, tombé de haut et utilisable uniquement en remote ou avec un autre écran.. C'est installé avec Windows 10 et je prends en remote avec TeamViewer. J'ai mon Jeedom qui tourne dans VirtualBox et S.A.R.A.H. sur le windows Consommation en charge avec JD et SARAH: 12W à 15W incluant un UPS avec shutdown automatique svp... (la batterie est encore bonne) J'ai presque envie de relancer ma VM xpenology pour transcoder, là il y a plus de hummph que avec mon DS 412+... C'est tout nouveau, je suis très content de ma solution... avant Jeedom tournait sur mon pc principal qui bouffait entre 70 et 90W en permanence...
  24. Tout est dans le titre. Il s'agit d'un simple device virtuel permettant de rebooter ou arreter un serveur synology. L'idée est inspirée de la solution de Labomatik pour QNAP La solution est tres tres largement inspirée du module virtuel de lazer permettant de piloter la surveillance station ... effectivement, je n'ai pas inventé grand chose. Toute la mécanique d'authentification est issue du dev de Lazer (que je remercie au passage). Les fonctions que l'on exploite ici ne sont pas officiellement mise à dispo par l'API Synology, mais un peu de reverse engeneering permet de retrouver ce qui est fait par l'interface web du synology. La configuration est tres simple : - Paramétrer l'adresse IP et le port du device virtuel avec l'adresse ip et le port du synology ==> Il doit s'agir d'un port HTTP. La solution ne supporte pas l'HTTPS. Dans chaque bouton, remplacer les variables par un login / password existant sur votre synology. Attention : Il doit s'agir d'un utilisateur ayant des droits admin Ajouté au virtuel device de Lazer, nous voilà aussi bien équipé que les utilisateurs QNAP. Plus de jaloux! Une remarque pour ceux qui souhaitent égallement redémarrer leur synology via la HC2 : Tous les synology ne supportent pas le Wake On Lan. Plus d'info : https://www.synology.com/fr-fr/knowledgebase/faq/437 Synology.vfib Icone pour le device virtuel :
  25. Pour faire face au problème récurrent de désynchronisation de l'horloge du HC2 voici un vd très largement inspiré par le support Fibaro cf. internal clock Homecenter is slow Il fonctionne a merveille sur mon HC2 qui n'est plus a la traine maintenant La synchronisation avec le serveur NTP sera faite une fois par jour en automatique par le VD mais il est aussi possible de faire une demande en manuel en cliquant sur le bouton Clock Sync dans le détail du VD ou sur le bouton du VD sur la home du HC2. Voici la miniature pour le vd: Pour la configuration du vd c'est très simple: après l'importation dans le HC2 et renseigné l'adresse IP et le port du HC2 dans l'onglet avancé il faut éditer le code du main loop et de modifier la variable synchroTime avec l'heure de mise à jour. Puis editer le code du bouton btnSync et de modifier les variables username et password avec votre userid et votre password admin de votre HC2 afin de pousser la modification sur votre HC2 par l' API Settings.... Le fichier vfib a importer sur le HC2: Clock_Sync.vfib PS: Si l'importation ne marche pas depuis le HC2, veuillez utiliser le Toolkit pour importer le vd Cette solution est du bidouillage mais cela marche très bien donc pour le moment cela me convient ! Amusez-vous bien...
×