Page 1 of 1

Updating virtual (weather) devices through LUA

Posted: Friday 15 April 2016 12:27
by marmachine
Hi All,

I'm working on an event script that performs a call to Wunderground's API and then updates several (manually created) virtual devices.
First of all, the reasons why i started on this:
  1. Devices created through the Domoticz virtual weather device, combine values that i'd like to see seperated (temp, hum, baro)
  2. I was looking for a solution to control my screens, to only lower them when the sun is shining (virtual lux sensor)
  3. Since i've found the virtual Lux sensor script, i figured that one API call would be anough, instead of both the virtual weather device and the virtual lux sensor script calling the same API (remember WU limitations)
  4. I want to be control of things through event scripting
Now, so far so good, i have my devices setup, killed (disabled) the virtual weather station functionality and am now updating the created devices through an event. (in a 5 minute interval)
However, my script needs quite some time so i find errors in my logging about the script running over 10 sec. I've discovered that this has to do with the way i am currently updating some devices (through a cURL command).

To my humble opinion though, i think that cURL is over the top when you only need to update internal values... let me explain a bit more in detail;
I can set my temperature device through LUA like this:

Code: Select all

['UpdateDevice'] = tostring(idxTemperature)..'|0|'..tostring(temperature)
But since i couldn't find a way to update my Baro in a similar way, and i could only find cURL information, i am now updating this way:

Code: Select all

cmd = "http://192.168.2.100:8080/json.htm?type=command&param=udevice&idx="..idxPressure.."&nvalue=0&svalue="..pressure..";"..trend
        result = os.execute('curl "'..cmd..'"')
Well, i've found json info here: https://www.domoticz.com/wiki/Domoticz_API/JSON_URL's, the 'UpdateDevice' method is not mentioned here and i cannot find any information on that either.

Someone here with some advice on this matter perhaps?
Thanks!

Re: Updating virtual (weather) devices through LUA

Posted: Friday 15 April 2016 23:24
by georgesattali
hello,

I understand a barometer waits for 5 values : TEMP;HUM;HUM_STAT;BAR;BAR_FOR
have u tried this ?

Code: Select all

['UpdateDevice2'] = idxPressure..'|0|' .. TEMP .. '; '.. HUM .. ';' .. HUM_STAT .. '; '..pressure ..';'.. trend
- if the device is a barometer, temp, hum, hum_stat must be given, even if nul,
- tostring is not mandatory and I dislike them, so ...
- must be not UpdateDevice if u already have one in the script => UpdateDevice2
- trend must be integer between 0 to 4 (BAR_FOR ?)
- maybe check first what values are returned by otherdevices_svalues['Pressure']

Re: Updating virtual (weather) devices through LUA

Posted: Friday 22 April 2016 10:28
by marmachine
Okay, thanks @georgesattali, i am now testing your suggestion, it seems to work but requires some tweeking;
My Pressure device showed temperature value as pressure: 12.2 hPa, so your suggestion works, but should be as mentioned below i think?

Code: Select all

commandArray[indexArray] = {['UpdateDevice'] = idxPressure..'|0|' .. pressure .. '; '.. humidity .. ';' .. humidity_status .. '; '.. temperature ..';'.. trend}
My (debug) log now shows:

Code: Select all

2016-04-22 11:51:03.689 LUA: | ------------------------------------------------ |
2016-04-22 11:51:03.689 LUA: | =============== API Wunderground =============== |
2016-04-22 11:51:03.689 LUA: | ------------------------------------------------ |
2016-04-22 11:51:03.689 LUA: | wuAPIkey = xxx
2016-04-22 11:51:03.689 LUA: | now updating the data and lastupdate uservariable
2016-04-22 11:51:03.689 LUA: | curl http://api.wunderground.com/api/xxx/conditions/q/country/city.json
2016-04-22 11:51:03.689 LUA: | Lat: latitude | Long: longtitude | Alt: 3.00000000
2016-04-22 11:51:03.689 LUA: | Tijdstip van waarneming: Fri, 22 Apr 2016 11:50:10 +0200
2016-04-22 11:51:03.689 LUA: | pressure_mb: 1021 hPa | trend: 0
2016-04-22 11:51:03.689 LUA: | temperatuur: 12.2 C | humidity: 59%
2016-04-22 11:51:03.689 LUA: | gevoelstemperatuur: 12.2 C
2016-04-22 11:51:03.689 LUA: | zicht: 10.0 km
2016-04-22 11:51:03.689 LUA: | wind: NE (49) | snelheid: 9.7 km/h | windvlaag: 16.1 km/h
2016-04-22 11:51:03.689 LUA: | neerslag vandaag: 0 mm | neerslag uur: 0 mm
2016-04-22 11:51:03.689 LUA: | UV: 3.7 | solar radiation: 823 Watt/m2
2016-04-22 11:51:03.689 LUA: | weather: Mostly Cloudy
2016-04-22 11:51:03.689 LUA: | ------------------------------------------------ |
2016-04-22 11:51:03.689 LUA: | ------------ updating device values ------------ |
2016-04-22 11:51:03.689 LUA: | ------------------------------------------------ |
2016-04-22 11:51:03.689 LUA: | Temperature device updated with value: 12.2
2016-04-22 11:51:03.689 LUA: | Temperature realfeel device updated with value: 12.2
2016-04-22 11:51:03.689 LUA: | Humidity device updated with value: 59%
2016-04-22 11:51:03.689 LUA: | Pressure device updated with value: 1021
2016-04-22 11:51:03.690 LUA: | Visibility device updated with value: 10.0
2016-04-22 11:51:03.690 LUA: | Solar device updated with value: 823
2016-04-22 11:51:03.690 LUA: | Weather device updated with value: Mostly Cloudy
...
I am updating several (virtual) devices, below is (part of) my script with the JSON call to WU which actually delivers all the info for various weather devices, this part works like a charm! I am using the returned values to set my devices.

Code: Select all

--  perform the API Wunderground call
    cmd = 'curl http://api.wunderground.com/api/'..wuAPIkey..'/conditions/q/'..country..'/'..city..'.json'
    local config=assert(io.popen(cmd))
    local location = config:read('*all')
    config:close()
    local jsonLocation = json:decode(location)

    -- get the results from the call
    local latitude              = jsonLocation.current_observation.display_location.latitude
    local longitude             = jsonLocation.current_observation.display_location.longitude
    local altitude              = jsonLocation.current_observation.display_location.elevation
    local observation_timestamp = jsonLocation.current_observation.observation_time_rfc822
    local temperature           = jsonLocation.current_observation.temp_c
    local temperature_realfeel  = jsonLocation.current_observation.feelslike_c
    local humidity              = jsonLocation.current_observation.relative_humidity
    local pressure              = jsonLocation.current_observation.pressure_mb
    local pressure_trend        = jsonLocation.current_observation.pressure_trend
    local visibility            = jsonLocation.current_observation.visibility_km
    local wind_dir              = jsonLocation.current_observation.wind_dir
    local wind_deg              = jsonLocation.current_observation.wind_degrees
    local wind_speed            = jsonLocation.current_observation.wind_kph
    local wind_gust             = jsonLocation.current_observation.wind_gust_kph
    local rain_today            = jsonLocation.current_observation.precip_today_metric
    local rain_hour             = jsonLocation.current_observation.precip_1hr_metric
    local uv                    = jsonLocation.current_observation.UV
    local solar                 = jsonLocation.current_observation.solarradiation
    local weather               = jsonLocation.current_observation.weather
With the above variables i am now successfully setting the below (virtual) devices;

Code: Select all

    ----------------------------
    -- update virtual sensors --
    ----------------------------

    -- For more information on the json commands, see: https://www.domoticz.com/wiki/Domoticz_API/JSON_URL's

    if ((idxTemperature) and (temperature)) then
        commandArray[indexArray] = {['UpdateDevice'] = tostring(idxTemperature)..'|0|'..tostring(temperature)}
        indexArray=indexArray+1
        if( DEBUG == 1) then print("| Temperature device updated with value: "..tostring(temperature)) end
    end

    if ((idxTemperature_realfeel) and (temperature_realfeel)) then
        commandArray[indexArray] = {['UpdateDevice'] = tostring(idxTemperature_realfeel)..'|0|'..tostring(temperature_realfeel)}
        indexArray=indexArray+1
        if( DEBUG == 1) then print("| Temperature realfeel device updated with value: "..tostring(temperature_realfeel)) end
    end

    if ((idxHumidity) and (humidity)) then

        -- Humidity_status can be one of:
        -- 0=Normal 1=Comfortable 2=Dry 3=Wet

        commandArray[indexArray] = {['UpdateDevice'] = tostring(idxHumidity)..'|'..humidity..'|0'}
        indexArray=indexArray+1
        if( DEBUG == 1) then print("| Humidity device updated with value: "..tostring(humidity)) end
    end
       
    if ((idxPressure) and (pressure)) then
        if (pressure_trend) then trend=tostring(pressure_trend) else trend="0" end
        
        pressure = tonumber(pressure)
        
        -- This 'trend' is still experimental! --
        -------------------------------------------
        -- mapping for trend
        --    Barometer forecast can be one of:
        --    0 = No info
        --    1 = Sunny
        --    2 = Partly cloudy
        --    3 = Cloudy
        --    4 = Rain

        if (trend == "0") then 
            if      (pressure > 1013)   then trend = "1" 
            elseif  (pressure > 987)    then trend = "2" 
            elseif  (pressure < 987)    then trend = "3"
            end
        elseif (trend == "+") then
            if      (pressure > 1013)   then trend = "1" 
            elseif  (pressure > 987)    then trend = "2" 
            elseif  (pressure < 987)    then trend = "2"
            end
        elseif (trend == "-") then
            if      (pressure > 1013)   then trend = "3" 
            elseif  (pressure > 987)    then trend = "4" 
            elseif  (pressure < 987)    then trend = "4"
            end
        else
            trend = "0"
        end

	-- This 'humidity' is still experimental! --
        -------------------------------------------
        -- Humidity_status can be one of:
        -- 0=Normal 1=Comfortable 2=Dry 3=Wet
        humidity_status = 0

        commandArray[indexArray] = {['UpdateDevice'] = idxPressure..'|0|' .. pressure .. '; '.. humidity .. ';' .. humidity_status .. '; '.. temperature ..';'.. trend}
        indexArray=indexArray+1
        if( DEBUG == 1) then print("| Pressure device updated with value: "..tostring(pressure)) end
    end

    if ((idxVisibility) and (visibility)) then
        commandArray[indexArray] = {['UpdateDevice'] = tostring(idxVisibility)..'|0|'..visibility}
        indexArray=indexArray+1
        if( DEBUG == 1) then print("| Visibility device updated with value: "..tostring(visibility)) end
    end

    if ((idxSolar) and (solar)) then
        commandArray[indexArray] = {['UpdateDevice'] = tostring(idxSolar)..'|0|'..tonumber(solar)}
        indexArray=indexArray+1
        if( DEBUG == 1) then print("| Solar device updated with value: "..tostring(solar)) end
    end

    if ((idxWeather) and (weather)) then
        commandArray[indexArray] = {['UpdateDevice'] = tostring(idxWeather)..'|0|'..tostring(weather)}
        indexArray=indexArray+1
        if( DEBUG == 1) then print("| Weather device updated with value: "..tostring(weather)) end
    end
How to set the BELOW (virtual) devices through UpdateDevice commandArray?
When setting through JSON this will result in an error telling that the script has been running over 10 seconds and after a while Domoticz will even crash!! (hangs)
Other than the JSON URL's i haven't been able to find any info on setting these devices, so help is very much welcome and appreciated
  • Wind
  • Rain
  • UV

Code: Select all

    if (idxRain) then
-- old command
--        cmd = 'http://192.168.2.100:8080/json.htm?type=command&param=udevice&idx='..idxRain..'&nvalue=0&svalue='..tostring(rain_hour)..';'..tostring(rain_today)
--        result = os.execute('curl "'..cmd..'"')

--        command = '/json.htm?type=command&param=udevice&idx='..idxRain..'&nvalue=0&svalue='..tostring(rain_hour)..';'..tostring(rain_today)
--        result  = process_device_values(command)
        
        result = "halted"
        if (result == nil) then result = "FAILED! (command: "..cmd..")" else result = tostring(result) end
        if( DEBUG == 1) then print("| Rain device updated, result: "..result) end
    end

    if ((idxUv) and (uv)) then
-- old command
--        commandArray[indexArray] = {['UpdateDevice'] = tostring(idxUv)..'|'..uv..'|1'}
--        indexArray=indexArray+1

--        command = '/json.htm?type=command&param=udevice&idx='..idxUv..'&nvalue=0&svalue='..uv..';0'
--        result  = process_device_values(command)

        result = "halted"        
        if (result == nil) then result = "FAILED! (command: "..cmd..")" else result = tostring(result) end
        if( DEBUG == 1) then print("| Rain device updated, result: "..result) end
    end

    if ((idxWind) and (wind_speed)) then
-- old command
--        cmd = 'http://192.168.2.100:8080/json.htm?type=command&param=udevice&idx='..idxWind..'&nvalue=0&svalue='..wind_deg..';'..wind_dir..';'..wind_speed..';'..wind_gust..';22;24'
--        result = os.execute('curl "'..cmd..'"')

--        command = '/json.htm?type=command&param=udevice&idx='..idxWind..'&nvalue=0&svalue='..wind_deg..';'..wind_dir..';'..wind_speed..';'..wind_gust..';22;24'
--        result  = process_device_values(command)
        
        result = "halted"
        if (result == nil) then result = "FAILED! (command: "..cmd..")" else result = tostring(result) end
        if( DEBUG == 1) then print("| Rain device updated, result: "..result) end
        -- still need to process and set: wind_dir ("..wind_dir..") wind_deg ("..wind_deg..") wind_speed ("..wind_speed..") wind_gust ("..wind_gust..")")
    end 

Re: Updating virtual (weather) devices through LUA

Posted: Friday 22 April 2016 19:08
by georgesattali
Hello,
I should have told you the place to find the good infos : https://www.domoticz.com/wiki/Domoticz_ ... L%27s#Wind

A "wind" device waits for 7 (waouh) values :
Wind
/json.htm?type=command&param=udevice&idx=IDX&nvalue=0&svalue=WB;WD;WS;WG;22;24
IDX = id of your device (This number can be found in the devices tab in the column "IDX")
WB = Wind bearing (0-359)
WD = Wind direction (S, SW, NNW, etc.)
WS = 10 * Wind speed [m/s]
WG = 10 * Gust [m/s]
22 = Temperature
24 = Temperature Windchill

I believe, but I haven't tested yet that you can update this kind of device through commandArray:

Code: Select all

commandArray[indexArray] = 
  {
      ['UpdateDevice'] = tostring(idxWind)..'|0|'..tostring(WB)
                  ..'|'..tostring(WD)
                  ..'|'..tostring(WS)
                  ..'|'..tostring(WG)
                  ..'|'..tostring(22)
                  ..'|'..tostring(24)
  }
It seems that UV absolutely need a 0 at the end :

Code: Select all

commandArray[indexArray] = 
   {
     ['UpdateDevice'] = tostring(idxUV)..'|0|'..tostring(UV)
                                                           ..'|'..'0'
   }
Rain wants 2 values : RAINRATE = amount of rain in last hour and RAINCOUNTER = continues counter of fallen Rain in mm
etc...

Bye, GD

Re: Updating virtual (weather) devices through LUA

Posted: Saturday 23 April 2016 11:06
by marmachine
A "wind" device waits for 7 (waouh) values :
Wind
/json.htm?type=command&param=udevice&idx=IDX&nvalue=0&svalue=WB;WD;WS;WG;22;24
IDX = id of your device (This number can be found in the devices tab in the column "IDX")
WB = Wind bearing (0-359)
WD = Wind direction (S, SW, NNW, etc.)
WS = 10 * Wind speed [m/s]
WG = 10 * Gust [m/s]
22 = Temperature
24 = Temperature Windchill
That is exactly what i think i have tried to do on the WIND device, but once again tested, but doesn't update!
My command string (printed to log) was: ['UpdateDevice'] = 88|0|29|NNO|16.1|27.4|8.6|6

SOLVED!
The solution to the matter of not updating is that the seperators are wrong!
The Update device command string should be:
['UpdateDevice'] = 88|0|29;NNO;16.1;27.4;8.6;6


Note: wind values first seemed to be incorrect, but they are actually correct!

Wunderground.com
"wind_kph":20.9,
"wind_gust_kph":"33.8",

Conversion before update

Code: Select all

-- WS = 10 * Wind speed [m/s]
wind_speed  = 10*(wind_speed /3.6)  -- calculate the windspeed value; convert (km/h to m/s) and * 10
-- WG = 10 * Gust [m/s]
wind_gust   = 10*(wind_gust /3.6)   -- calculate the windgust value; convert (km/h to m/s) and * 10

['UpdateDevice'] = tostring(idxWind)..'|0|'..tostring(wind_deg)..';'..tostring(wind_dir)..';'..tostring(wind_speed)..';'..tostring(wind_gust)..';'..tostring(temperature)..';'..tostring(windchill)
My log
Log shows the values used for the Wind device update
2016-04-24 11:01:03.660 LUA: | Wind device (88) updated with value: 58.055555555556 and Windgust device with value 93.888888888889

svalues from wind
When i request the values from the wind device, it returns the following values (similar to the update values)
Windmeter values: 325;NW;58.055555555556;93.888888888889;6.4;3

To convert the values back to km/h value, you do the opposite of the conversion before update;

Code: Select all

-- convert windspeeds from to km/h value
sWindSpeed  = (sWindSpeed * 3.6) / 10
sWindGust   = (sWindGust * 3.6) / 10

Re: Updating virtual (weather) devices through LUA

Posted: Friday 02 June 2017 22:35
by Flopp
this was working for me to update a Dummy:Electric(Instant+Counter)

Code: Select all

cmd = "http://x.x.x.x:8080/json.htm?type=command&param=udevice&idx=272&nvalue=0&svalue="..hushall_w..";"..tot_hushall_kwh

os.execute("curl '"..cmd.."'")