This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

Weather Info from API
#1
Hello, 
Please, I hope you could help me in my issue
However, I was trying to get the weather infomation from apixu.com and write them on the KNX bus.
I just followed the exemple on the openrb.com this one (https://openrb.com/featch-weather-forecast-from-apixu), I only changed the key variable as it's mentioned in the exemple.

This is the scheduled script that I used.
Code:
require('json')
https = require('ssl.https')
escape = require('socket.url').escape

key = '737ad147e5be532e3d78995a68f4a160'
location = 'Norway'

url = 'https://api.apixu.com/v1/forecast.json?key=%s&q=%s&days=2'
url = string.format(url, key, escape(location))

res = https.request(url)

data = json.pdecode(res)
if type(data) ~= 'table' then
  alert('failed to load weather data')
  return
end

if data.error then
  log('error', data.error)
  return
end

current = data.current
today = data.forecast.forecastday[ 1 ].day
tomorrow = data.forecast.forecastday[ 2 ].day

-- log(current, today, tomorrow)

-- temperature in C
grp.write('32/1/1', current.temp_c)
-- "feels like" temperature in C
grp.write('32/1/2', current.feelslike_c)
-- humidity as percentage
grp.write('32/1/3', current.humidity)
-- wind speed in kilometers per hour
grp.write('32/1/4', current.wind_kph)
-- uv index
grp.write('32/1/5', current.uv)
-- weather condition text
grp.write('32/1/6', current.condition.text)
-- pressure in millibars
grp.write('32/1/7', current.pressure_mb)
-- precipitation amount in millimeters
grp.write('32/1/8', current.precip_mm)

-- minimum temperature in celsius for the day
grp.write('32/2/1', today.mintemp_c)
-- maximum temperature in celsius for the day
grp.write('32/2/2', today.maxtemp_c)
-- average temperature in celsius for the day
grp.write('32/2/3', today.avgtemp_c)
-- average humidity as percentage
grp.write('32/2/4', today.avghumidity)
-- maximum wind speed in kilometers per hour
grp.write('32/2/5', today.maxwind_kph)
-- uv index
grp.write('32/2/6', today.uv)
-- weather condition text
grp.write('32/2/7', today.condition.text)
-- total precipitation in millimeters
grp.write('32/2/8', today.totalprecip_mm)
-- minimum temperature in celsius for the day
grp.write('32/3/1', tomorrow.mintemp_c)
-- maximum temperature in celsius for the day
grp.write('32/3/2', tomorrow.maxtemp_c)
-- average temperature in celsius for the day
grp.write('32/3/3', tomorrow.avgtemp_c)
-- average humidity as percentage
grp.write('32/3/4', tomorrow.avghumidity)
-- maximum wind speed in kilometers per hour
grp.write('32/3/5', tomorrow.maxwind_kph)
-- uv index
grp.write('32/3/6', tomorrow.uv)
-- weather condition text
grp.write('32/3/7', tomorrow.condition.text)
-- total precipitation in millimeters
grp.write('32/3/8', tomorrow.totalprecip_mm)


No data was found on those groupe addresses, 
Or if you could give me any other solution, I only wants to write 1 on the KNX bus if there's a snow tomorrow, the place is Bergen in Norway

Very grateful in advance
Reply
#2
yr.no provides free detailed forecast API.
This example will check if there will be snow in the next day. You only need to adjust your location (latitude/longitude) and the status object address. There might be some limits on how often the API can be accessed so create a scheduled script that runs every 3 hours or so.
Code:
latitude = 60.3894
longitude = 5.33
status = '1/1/1'

json = require('json')
http = require('socket.http')

args = 'lat=' .. latitude .. '&lon=' .. longitude
url = 'https://api.met.no/weatherapi/locationforecast/2.0/compact?' .. args
mac = 0
io.readfile('/sys/class/net/eth0/address'):gsub('%x%x', function(v)
  mac = mac * 256 + tonumber(v, 16)
end)
http.USERAGENT = 'LM ' .. mac

res, err = http.request(url)
data = json.pdecode(res)

if type(data) == 'table' then
  date = os.date('*t')
  date.day = date.day + 1
  time = os.time(date)
  timestamp = os.date('%Y-%m-%d', time)

  snow = false

  for i, entry in ipairs(data.properties.timeseries) do
    if entry.time:sub(1, #timestamp) == timestamp then

      next1h = entry.data.next_1_hours
      code = ''

      if type(next1h) == 'table' and type(next1h.summary) == 'table' then
        code = next1h.summary.symbol_code or ''
      end

      if code:find('snow') then
        snow = true
        break
      end
    end
  end

  grp.checkwrite(status, snow)
end
Reply
#3
Hi Admin,

May I ask for a little bit of help also?
Do you experience problems with the setup explained here: https://openrb.com/featch-weather-forecast-from-apixu
Have and account and key but I get the following message:

"#################################################################################################################################"
1 "#                                                                                                                              #"
2 "# IMPORTANT - PLEASE UPDATE YOUR API ENDPOINT                                                                                  #"
3 "#                                                                                                                              #"
4 "# This API endpoint is deprecated and has now been shut down. To keep using the apixu API, please update your integration      #"
5 "# to use the new weatherstack API endpoint, designed as a simple drop-in replacement.                                          #"
6 "# You will be required to create an account at https://weatherstack.com and obtain an API access key.                          #"
7 "#                                                                                                                              #"
8 "# For more information on how to upgrade please visit our Github Tutorial at: https://github.com/apilayer/weatherstack#readme  #"
9 "#                                                                                                                              #"
a "#################################################################################################################################"

Thank you in advance!
Reply
#4
The free tier in weatherstack does not provide forecast data, only current conditions. Consider using yr.no instead. We will publish an updated integration script for yr.no next week.
Reply
#5
Thank you for your replay!
I've been using YR until recently but it stopped. Looking forward to your YR script update Smile
Reply
#6
Hi,

may be some news about new yr.no weather script? Looks like one of the best free weather informers now..

Alex
Reply
#7
Hi, here is new yr weather script.

Code:
-- Please comment objects which you are not using, comment also grp.write() at the bottom of script

--latitude = 60.3894 -- Bergen
--longitude = 5.33   -- Bergen
latitude = 56.9496  -- Riga
longitude = 24.1052 -- Riga
--latitude = 51.5072 -- London
--longitude = 0.1276 -- London

--[[
status_temp = '32/1/13'           -- group address of temperature, should be float
status_pressure = '32/1/14'       -- air pressure, should be float
status_humidity = '32/1/15'       -- relative humidity, should be float
status_wind_direction = '32/1/16' -- wind direction, should be float
status_wind_speed = '32/1/17'     -- wind speed, should be float
status_uv_index = '32/2/4'        -- UV index, should be float
status_feelslike_temp = '32/2/3'  -- feels like temperature, should be float

status_rain_today = '32/1/11'     -- today's rain object, should be boolean
status_snow_today = '32/1/12'     -- today's snow object, should be boolean

status_min_temp_today = '32/1/20'       -- today's minimum air temperature, float
status_max_temp_today = '32/1/21'       -- today's maximum air temperature, float
status_min_pressure_today = '32/1/22'   -- minimum air pressure, float
status_max_pressure_today = '32/1/23'   -- maximum air pressure, float
status_min_wind_speed_today = '32/1/24' -- minimum wind speed, float
status_max_wind_speed_today = '32/1/25' -- maximum wind speed, float
status_min_uv_today = '32/2/5'          -- minimum UV today, float
status_max_uv_today = '32/2/6'          -- maximum UV today, float

status_rain_tomor = '32/1/9'   -- tomorrow's rain object
status_snow_tomor = '32/1/10'  -- tomorrow's snow object

status_min_temp_tomor = '32/1/26'
status_max_temp_tomor = '32/1/27'
status_min_pressure_tomor = '32/1/28'
status_max_pressure_tomor = '32/1/29'
status_min_wind_speed_tomor = '32/1/30'
status_max_wind_speed_tomor = '32/1/31'
status_min_uv_tomor = '32/2/7'
status_max_uv_tomor = '32/2/8'
--]]

--[[]]
status_temp = grp.create({ datatype = dt.float16, address = '33/1/1', name = 'current_temp',})
status_pressure = grp.create({ datatype = dt.float16, address = '33/1/2', name = 'current_press',})
status_humidity = grp.create({ datatype = dt.float16, address = '33/1/3', name = 'current_humid',})
status_wind_direction = grp.create({ datatype = dt.float16, address = '33/1/4', name = 'current_wind_dir',})
status_wind_speed = grp.create({ datatype = dt.float16, address = '33/1/5', name = 'current_wind_sp',})
status_uv_index = grp.create({ datatype = dt.float16, address = '33/1/6', name = 'current_uv_index',})
status_feelslike_temp = grp.create({ datatype = dt.float16, address = '33/1/7', name = 'current_feels_temp',})

status_rain_today = grp.create({ datatype = dt.bool, address = '33/1/8', name = 'rain_today',})
status_snow_today = grp.create({ datatype = dt.bool, address = '33/1/9', name = 'snow_today',})

status_min_temp_today = grp.create({ datatype = dt.float16, address = '33/1/10', name = 'today_temp_min',})
status_max_temp_today = grp.create({ datatype = dt.float16, address = '33/1/11', name = 'today_temp_max',})
status_min_pressure_today = grp.create({ datatype = dt.float16, address = '33/1/12', name = 'today_press_min',})
status_max_pressure_today = grp.create({ datatype = dt.float16, address = '33/1/13', name = 'today_press_max',})
status_min_wind_speed_today = grp.create({ datatype = dt.float16, address = '33/1/14', name = 'today_wind_min',})
status_max_wind_speed_today = grp.create({ datatype = dt.float16, address = '33/1/15', name = 'today_press_max',})
status_min_uv_today = grp.create({ datatype = dt.float16, address = '33/1/16', name = 'today_uv_min',})
status_max_uv_today = grp.create({ datatype = dt.float16, address = '33/1/17', name = 'today_uv_max',})

status_rain_tomor = grp.create({ datatype = dt.bool, address = '33/1/18', name = 'rain_tomor',})
status_snow_tomor = grp.create({ datatype = dt.bool, address = '33/1/19', name = 'snow_tomor',})

status_min_temp_tomor = grp.create({ datatype = dt.float16, address = '33/1/20', name = 'tomor_temp_min',})
status_max_temp_tomor = grp.create({ datatype = dt.float16, address = '33/1/21', name = 'tomor_temp_max',})
status_min_pressure_tomor = grp.create({ datatype = dt.float16, address = '33/1/22', name = 'tomor_press_min',})
status_max_pressure_tomor = grp.create({ datatype = dt.float16, address = '33/1/23', name = 'tomor_press_max',})
status_min_wind_speed_tomor = grp.create({ datatype = dt.float16, address = '33/1/24', name = 'tomor_wind_min',})
status_max_wind_speed_tomor = grp.create({ datatype = dt.float16, address = '33/1/25', name = 'tomor_wind_max',})
status_min_uv_tomor = grp.create({ datatype = dt.float16, address = '33/1/26', name = 'tomor_uv_min',})
status_max_uv_tomor = grp.create({ datatype = dt.float16, address = '33/1/27', name = 'tomor_uv_max',})
--]]

rain_tod_YR = false        -- is rainy or not (for today)
snow_tod_YR = false        -- is snowy or not (for today)
rain_tom_YR = false        -- is rainy or not (for tomorrow)
snow_tom_YR = false        -- is snowy or not (for tomorrow)

-- current temperature, air pressure, humidity, wind direction and speed
temperature_YR = -273    -- temperature in degree Celsius
air_pressure_YR = -1     -- air pressure in hPa
humidity_YR = -1         -- air humidity in %
wind_direction_YR = -1   -- wind direction in degrees [0; 360)
wind_speed_YR = -1       -- wind speed in m/s
uv_index_YR = -1         -- UV index
feelslike_temp_YR = -273 -- feels like temperature in degree Celsius


function init_min_max_table() -- initialize table for minimum, maximum temperature, pressure, windspeed
  local min_max = {}
  min_max.min_t = 8000 -- minimum temperature for today
  min_max.max_t = -273 -- maximum temperature for today
  min_max.min_p = 8000 -- minimum pressure for today
  min_max.max_p = -1   -- maximum pressure for today
  min_max.min_w = 8000 -- minimum wind speed for today
  min_max.max_w = -1   -- maximum wind speed for today
  min_max.min_uv = 8000 -- minimum UV index
  min_max.max_uv = -1   -- maximum UV index
 
  return min_max
end


function set_timestamp(day) -- if day = 0 today; if day = 1 tomorrow, if day = 2 day after tomorrow
    local date = os.date('*t')
  date.day = date.day + day
  local time = os.time(date)
  return os.date('%Y-%m-%d', time), date.hour -- timestamp and current hour
end


-- minimum maximum values of temperature, pressure and windspeed
function min_max_temp_press_wind(dat_tab, min_max_tab)
  min_max_tab.min_t = math.min(min_max_tab.min_t, dat_tab.air_temperature or 8000)
  min_max_tab.max_t = math.max(min_max_tab.max_t, dat_tab.air_temperature or -273)
  min_max_tab.min_p = math.min(min_max_tab.min_p, dat_tab.air_pressure_at_sea_level or 8000)
  min_max_tab.max_p = math.max(min_max_tab.max_p, dat_tab.air_pressure_at_sea_level or -1)
  min_max_tab.min_w = math.min(min_max_tab.min_w, dat_tab.wind_speed or 8000)
  min_max_tab.max_w = math.max(min_max_tab.max_w, dat_tab.wind_speed or -1)
  min_max_tab.min_uv = math.min(min_max_tab.min_uv, dat_tab.ultraviolet_index_clear_sky or 8000)
  min_max_tab.max_uv = math.max(min_max_tab.max_uv, dat_tab.ultraviolet_index_clear_sky or -1)
 
  return min_max_tab
end


function check_for_rain(next1h)
    local is_rainy = false
  local code = ''
 
  if type(next1h) == 'table' and type(next1h.summary) == 'table' then
    code = next1h.summary.symbol_code or ''
  end
 
  if code:find('rain') then
    is_rainy = true
  end
 
  return is_rainy
end


function check_for_snow(next1h)
    local is_snowy = false
  local code = ''
 
  if type(next1h) == 'table' and type(next1h.summary) == 'table' then
    code = next1h.summary.symbol_code or ''
  end
 
  if code:find('snow') then
    is_snowy = true
  end

  return is_snowy
end


function calc_heat_index(temperature, humidity)
  if temperature < 26.7 then
    log('for heat_index calculation temperature should be higher than +26.7 Celsius degree')
    return -273
  end
 
  if humidity < 0 or humidity > 100 then
    log('humidity should be in a range from 0 ... 100%')
    return -273
  end
 
  local T = temperature
  local H = humidity
  local c_1 = -8.785
  local c_2 = 1.611
  local c_3 = 2.339
  local c_4 = -0.146
  local c_5 = -0.0123
  local c_6 = -0.0164
  local c_7 = 0.00221
  local c_8 = 0.000725
  local c_9 = -0.00000358
  local heat_index = c_1+c_2*T+c_3*H+c_4*T*H+c_5*T*T+c_6*H*H+c_7*T*T*H+c_8*T*H*H+c_9*T*T*H*H
 
    return heat_index
end


function calc_wind_chill(temperature, wind_speed)
  if temperature > 10 then
    log('temperature should be less than +10.0 Celsius degree')
      return -273
  end
   
  if wind_speed < 0 or wind_speed > 49.2 then
      log('wind speed should be in a range 0 ... 49.2 m/s')
    return -273
  end
 
  local T_air = temperature -- air temperature Celsius degree
 
  local a = 0.62 -- coef
  local b = 0.51 -- coef
  local T_1 = 13.1 -- Celsius degree
  local T_2 = 14.6 -- Celsius degree
 
  local M_0 = 1.3333 -- m/s
  local M = wind_speed -- m/s
 
  local T_wind_chill
 
  if M > M_0 then
    T_wind_chill = (a*T_air + T_1) + (b*T_air - T_2)*(M/M_0)^0.16
  else
    T_wind_chill = T_air
  end
 
  return T_wind_chill
end


function calc_feelslike(temperature, wind_speed, humidity)
  local T_feelslike
 
    if temperature <= 10.0 then -- if less than 10.0 Celsius degree (or equal) then wind chill
    T_feelslike = calc_wind_chill(temperature, wind_speed)
  elseif temperature >= 26.7 then -- if more than 26.7 Celsius degree (or equal) then heat index
    T_feelslike = calc_heat_index(temperature, humidity)
  else -- other cases just return temperature
    T_feelslike = temperature
  end

  return T_feelslike
end


min_max_today = init_min_max_table() -- table for minimum maximum temperature, air pressure, wind direction
min_max_tomor = init_min_max_table() -- table for minimum maximum temperature, air pressure, wind direction

json = require('json')
http = require('socket.http')

args = 'lat=' .. latitude .. '&lon=' .. longitude

--url = 'https://api.met.no/weatherapi/locationforecast/2.0/compact?' .. args
url = 'https://api.met.no/weatherapi/locationforecast/2.0/complete?' .. args

mac = 0
io.readfile('/sys/class/net/eth0/address'):gsub('%x%x', function(v)
  mac = mac * 256 + tonumber(v, 16)
end)
http.USERAGENT = 'LM ' .. mac

res, err = http.request(url)
data = json.pdecode(res)


if type(data) == 'table' then
  timestamp, hour = set_timestamp(0) -- current day
 
  if hour < 10 then
    timestamp_current_hour = timestamp .. 'T0' .. hour .. ':00:00Z' -- time stamp for current hour
  else
    timestamp_current_hour = timestamp .. 'T' .. hour .. ':00:00Z'  -- time stamp for current hour
  end
 
  --log('timestamp = ' .. timestamp)
 
  timestamp_next = set_timestamp(1) -- timestamp for tomorrow
  --log('timestamp_next = ' .. timestamp_next)
 
  --timestamp_after_next = set_timestamp(2) -- timestamp for day after tomorrow
  --log('timestamp_after_next = ' .. timestamp_after_next)
 
  --timestamp_after_after = set_timestamp(3) -- timestamp for day after day after tomorrow
  --log('timestamp_after_after = ' .. timestamp_after_after)
 
  for i, entry in ipairs(data.properties.timeseries) do 
   
    -- for weather now
    if entry.time == timestamp_current_hour then -- get data only for one hour (current hour)
      current_data = entry.data.instant.details
      if type(current_data) == 'table' then
        temperature_YR = current_data.air_temperature or -273           -- temperature in Celsius degree
        air_pressure_YR = current_data.air_pressure_at_sea_level or -1  -- air pressure in hPa
        humidity_YR = current_data.relative_humidity or -1              -- air humidity in %
        wind_direction_YR = current_data.wind_from_direction or -1      -- wind direction in degrees [0;360)
        wind_speed_YR = current_data.wind_speed or -1                   -- wind speed in m/s
        uv_index_YR = current_data.ultraviolet_index_clear_sky or -1    -- uv index
        feelslike_temp_YR = calc_feelslike(temperature_YR, wind_speed_YR, humidity_YR) -- feels like temperature in Celsius degree
      end
    end
   
    if entry.time:sub(1, #timestamp) == timestamp then -- checks remaining hours + 3 previous hours of current day
        current_data = entry.data.instant.details
      if type(current_data) == 'table' then
        min_max_today = min_max_temp_press_wind(current_data, min_max_today)
      end
     
      if rain_tod_YR == false then -- if detected rain does not check for rain
        rain_tod_YR = check_for_rain(entry.data.next_1_hours)
      end
     
      if snow_tod_YR == false then -- if detected snow does not check for snow
        snow_tod_YR = check_for_snow(entry.data.next_1_hours)
      end
    end
   
    if entry.time:sub(1, #timestamp_next) == timestamp_next then -- checks 24 hours of next day
      tomor_data = entry.data.instant.details
      if type(tomor_data) == 'table' then
        min_max_tomor = min_max_temp_press_wind(tomor_data, min_max_tomor)
      end
     
      if rain_tom_YR == false then -- if detected rain does not check for rain
        rain_tom_YR = check_for_rain(entry.data.next_1_hours)
      end
     
      if snow_tom_YR == false then -- if detected snow does not check for snow
        snow_tom_YR = check_for_snow(entry.data.next_1_hours)
      end
    end
 
  end

 
  -- data for current hour
  grp.write(status_temp, temperature_YR)
  grp.write(status_pressure, air_pressure_YR)
  grp.write(status_humidity, humidity_YR)
  grp.write(status_wind_direction, wind_direction_YR)
  grp.write(status_wind_speed, wind_speed_YR)
  grp.write(status_uv_index, uv_index_YR)
  grp.write(status_feelslike_temp, feelslike_temp_YR)
 
 
  -- data for today: rain, snow; min and max for temperature, pressure, wind
  grp.write(status_rain_today, rain_tod_YR)
  grp.write(status_snow_today, snow_tod_YR)
 
  grp.write(status_min_temp_today, min_max_today.min_t)
  grp.write(status_max_temp_today, min_max_today.max_t)
  grp.write(status_min_pressure_today, min_max_today.min_p)
  grp.write(status_max_pressure_today, min_max_today.max_p)
  grp.write(status_min_wind_speed_today, min_max_today.min_w)
  grp.write(status_max_wind_speed_today, min_max_today.max_w)
  grp.write(status_min_uv_today, min_max_today.min_uv)
  grp.write(status_max_uv_today, min_max_today.max_uv)
 
 
  -- data for tomorrow: rain, snow; min and max for temperature, pressure, wind
  grp.write(status_rain_tomor, rain_tom_YR)
  grp.write(status_snow_tomor, snow_tom_YR)
 
  grp.write(status_min_temp_tomor, min_max_tomor.min_t)
  grp.write(status_max_temp_tomor, min_max_tomor.max_t)
  grp.write(status_min_pressure_tomor, min_max_tomor.min_p)
  grp.write(status_max_pressure_tomor, min_max_tomor.max_p)
  grp.write(status_min_wind_speed_tomor, min_max_tomor.min_w)
  grp.write(status_max_wind_speed_tomor, min_max_tomor.max_w)
  grp.write(status_min_uv_tomor, min_max_tomor.min_uv)
  grp.write(status_max_uv_tomor, min_max_tomor.max_uv)
 
end

Attached Files
.lua   my_script_v12.lua (Size: 14.97 KB / Downloads: 17)
Reply
#8
Hi, super job is done!. Will test it in nearest time.

Some ideas for improvements/additional possibilities:

1. If weather info is needed for place where device is located - possible not to show coordinates directly in script but take them from system:

require('uci')

latitude = uci.get('genohm-scada.core.latitude')
latitude = tonumber(latitude) or 0

longitude = uci.get('genohm-scada.core.longitude')
longitude = tonumber(longitude) or 0

If 0 - no coordinates - should be entered than..;

2. Would be great if we can show group addresses for weather conditions in the beginning of script, because these groups will be created later in this script (addresses showed natively, not by names). I see it was planned to do so, but was commented.. For me groups 33/1/XX are used, For test I will manually change them in script;

3. In my existing weather script I use weather condition icons. So condition is taken from informer, than condition's icon is showed at visu...
May be ''symbol code'' info from yr.no we can add to script and use with icons?

4. how often we can start this script? Once a day? Some informers not allowed very often requests and can block them, or allows for additional payment..

BR,

Alex
Reply
#9
I have found out that, there was wrong name for object of maximum wind speed

was
Code:
status_max_wind_speed_today = grp.create({ datatype = dt.float16, address = '33/1/15', name = 'today_press_max',})

should be
Code:
status_max_wind_speed_today = grp.create({ datatype = dt.float16, address = '33/1/15', name = 'today_wind_max',})
Reply
#10
The updated version of weather script.
1.) Added possibility to read coordinates (latitude and longitude) from system.
2.) Changed data types of objects:
        a.) for humidity dt.scale
        b.) for uv_index dt.uint8
        c.) for pressure dt.uint16

Code:
-- Please comment objects which you are not using, comment also grp.write() at the bottom of script


--[[
-- You can set latitude and longitude in "Date time" option
-- go to LogicMachine->Utilities->Date and time

require('uci')

latitude = uci.get('genohm-scada.core.latitude') -- read latitude from system
latitude = tonumber(latitude) or 0

longitude = uci.get('genohm-scada.core.longitude') -- read longitude from system
longitude = tonumber(longitude) or 0

if(latitude == 0 and longitude == 0) then -- if cooridinates were not set in the system
  latitude = 51.5072 -- London
  longitude = 0.1276 -- London
end
--]]


-- you can set latitude and longitude manualy
-- (if you set coordinates using "Date time" do not forget to comment these two lines
latitude = 56.9496  -- Riga
longitude = 24.1052 -- Riga


--log('latitude = ' .. latitude)
--log('longitude = ' .. longitude)


--[[
status_temp = '32/1/13'           -- group address of temperature, should be float
status_pressure = '32/1/14'       -- air pressure, should be float
status_humidity = '32/1/15'       -- relative humidity, should be float
status_wind_direction = '32/1/16' -- wind direction, should be float
status_wind_speed = '32/1/17'     -- wind speed, should be float
status_uv_index = '32/2/4'        -- UV index, should be float
status_feelslike_temp = '32/2/3'  -- feels like temperature, should be float

status_rain_today = '32/1/11'     -- today's rain object, should be boolean
status_snow_today = '32/1/12'     -- today's snow object, should be boolean

status_min_temp_today = '32/1/20'       -- today's minimum air temperature, float
status_max_temp_today = '32/1/21'       -- today's maximum air temperature, float
status_min_pressure_today = '32/1/22'   -- minimum air pressure, float
status_max_pressure_today = '32/1/23'   -- maximum air pressure, float
status_min_wind_speed_today = '32/1/24' -- minimum wind speed, float
status_max_wind_speed_today = '32/1/25' -- maximum wind speed, float
status_min_uv_today = '32/2/5'          -- minimum UV today, float
status_max_uv_today = '32/2/6'          -- maximum UV today, float

status_rain_tomor = '32/1/9'   -- tomorrow's rain object
status_snow_tomor = '32/1/10'  -- tomorrow's snow object

status_min_temp_tomor = '32/1/26'
status_max_temp_tomor = '32/1/27'
status_min_pressure_tomor = '32/1/28'
status_max_pressure_tomor = '32/1/29'
status_min_wind_speed_tomor = '32/1/30'
status_max_wind_speed_tomor = '32/1/31'
status_min_uv_tomor = '32/2/7'
status_max_uv_tomor = '32/2/8'
--]]

--[[]]
status_temp = grp.create({ datatype = dt.float16, address = '33/1/1', name = 'current_temp',})
status_pressure = grp.create({ datatype = dt.uint16, address = '33/1/2', name = 'current_press',})
status_humidity = grp.create({ datatype = dt.scale, address = '33/1/3', name = 'current_humid',})
status_wind_direction = grp.create({ datatype = dt.float16, address = '33/1/4', name = 'current_wind_dir',})
status_wind_speed = grp.create({ datatype = dt.float16, address = '33/1/5', name = 'current_wind_sp',})
status_uv_index = grp.create({ datatype = dt.uint8, address = '33/1/6', name = 'current_uv_index',})
status_feelslike_temp = grp.create({ datatype = dt.float16, address = '33/1/7', name = 'current_feels_temp',})

status_rain_today = grp.create({ datatype = dt.bool, address = '33/1/8', name = 'rain_today',})
status_snow_today = grp.create({ datatype = dt.bool, address = '33/1/9', name = 'snow_today',})

status_min_temp_today = grp.create({ datatype = dt.float16, address = '33/1/10', name = 'today_temp_min',})
status_max_temp_today = grp.create({ datatype = dt.float16, address = '33/1/11', name = 'today_temp_max',})
status_min_pressure_today = grp.create({ datatype = dt.uint16, address = '33/1/12', name = 'today_press_min',})
status_max_pressure_today = grp.create({ datatype = dt.uint16, address = '33/1/13', name = 'today_press_max',})
status_min_wind_speed_today = grp.create({ datatype = dt.float16, address = '33/1/14', name = 'today_wind_min',})
status_max_wind_speed_today = grp.create({ datatype = dt.float16, address = '33/1/15', name = 'today_wind_max',})
status_min_uv_today = grp.create({ datatype = dt.uint8, address = '33/1/16', name = 'today_uv_min',})
status_max_uv_today = grp.create({ datatype = dt.uint8, address = '33/1/17', name = 'today_uv_max',})

status_rain_tomor = grp.create({ datatype = dt.bool, address = '33/1/18', name = 'rain_tomor',})
status_snow_tomor = grp.create({ datatype = dt.bool, address = '33/1/19', name = 'snow_tomor',})

status_min_temp_tomor = grp.create({ datatype = dt.float16, address = '33/1/20', name = 'tomor_temp_min',})
status_max_temp_tomor = grp.create({ datatype = dt.float16, address = '33/1/21', name = 'tomor_temp_max',})
status_min_pressure_tomor = grp.create({ datatype = dt.uint16, address = '33/1/22', name = 'tomor_press_min',})
status_max_pressure_tomor = grp.create({ datatype = dt.uint16, address = '33/1/23', name = 'tomor_press_max',})
status_min_wind_speed_tomor = grp.create({ datatype = dt.float16, address = '33/1/24', name = 'tomor_wind_min',})
status_max_wind_speed_tomor = grp.create({ datatype = dt.float16, address = '33/1/25', name = 'tomor_wind_max',})
status_min_uv_tomor = grp.create({ datatype = dt.uint8, address = '33/1/26', name = 'tomor_uv_min',})
status_max_uv_tomor = grp.create({ datatype = dt.uint8, address = '33/1/27', name = 'tomor_uv_max',})
--]]

rain_tod_YR = false        -- is rainy or not (for today)
snow_tod_YR = false        -- is snowy or not (for today)
rain_tom_YR = false        -- is rainy or not (for tomorrow)
snow_tom_YR = false        -- is snowy or not (for tomorrow)

-- current temperature, air pressure, humidity, wind direction and speed
temperature_YR = -273    -- temperature in degree Celsius
air_pressure_YR = -1     -- air pressure in hPa
humidity_YR = -1         -- air humidity in %
wind_direction_YR = -1   -- wind direction in degrees [0; 360)
wind_speed_YR = -1       -- wind speed in m/s
uv_index_YR = -1         -- UV index
feelslike_temp_YR = -273 -- feels like temperature in degree Celsius


function init_min_max_table() -- initialize table for minimum, maximum temperature, pressure, windspeed
  local min_max = {}
  min_max.min_t = 8000 -- minimum temperature for today
  min_max.max_t = -273 -- maximum temperature for today
  min_max.min_p = 8000 -- minimum pressure for today
  min_max.max_p = -1   -- maximum pressure for today
  min_max.min_w = 8000 -- minimum wind speed for today
  min_max.max_w = -1   -- maximum wind speed for today
  min_max.min_uv = 8000 -- minimum UV index
  min_max.max_uv = -1   -- maximum UV index
 
  return min_max
end


function set_timestamp(day) -- if day = 0 today; if day = 1 tomorrow, if day = 2 day after tomorrow
  local date = os.date('*t')
  date.day = date.day + day
  local time = os.time(date)
  return os.date('%Y-%m-%d', time), date.hour -- timestamp and current hour
end


-- minimum maximum values of temperature, pressure and windspeed
function min_max_temp_press_wind(dat_tab, min_max_tab)
  min_max_tab.min_t = math.min(min_max_tab.min_t, dat_tab.air_temperature or 8000)
  min_max_tab.max_t = math.max(min_max_tab.max_t, dat_tab.air_temperature or -273)
  min_max_tab.min_p = math.min(min_max_tab.min_p, dat_tab.air_pressure_at_sea_level or 8000)
  min_max_tab.max_p = math.max(min_max_tab.max_p, dat_tab.air_pressure_at_sea_level or -1)
  min_max_tab.min_w = math.min(min_max_tab.min_w, dat_tab.wind_speed or 8000)
  min_max_tab.max_w = math.max(min_max_tab.max_w, dat_tab.wind_speed or -1)
  min_max_tab.min_uv = math.min(min_max_tab.min_uv, dat_tab.ultraviolet_index_clear_sky or 8000)
  min_max_tab.max_uv = math.max(min_max_tab.max_uv, dat_tab.ultraviolet_index_clear_sky or -1)
 
  return min_max_tab
end


function check_for_rain(next1h)
  local is_rainy = false
  local code = ''
 
  if type(next1h) == 'table' and type(next1h.summary) == 'table' then
    code = next1h.summary.symbol_code or ''
  end
 
  if code:find('rain') then
    is_rainy = true
  end
 
  return is_rainy
end


function check_for_snow(next1h)
  local is_snowy = false
  local code = ''
 
  if type(next1h) == 'table' and type(next1h.summary) == 'table' then
    code = next1h.summary.symbol_code or ''
  end
 
  if code:find('snow') then
    is_snowy = true
  end

  return is_snowy
end


function calc_heat_index(temperature, humidity)
  if temperature < 26.7 then
    log('for heat_index calculation temperature should be higher than +26.7 Celsius degree')
    return -273
  end
 
  if humidity < 0 or humidity > 100 then
    log('humidity should be in a range from 0 ... 100%')
    return -273
  end
 
  local T = temperature
  local H = humidity
  local c_1 = -8.785
  local c_2 = 1.611
  local c_3 = 2.339
  local c_4 = -0.146
  local c_5 = -0.0123
  local c_6 = -0.0164
  local c_7 = 0.00221
  local c_8 = 0.000725
  local c_9 = -0.00000358
  local heat_index = c_1+c_2*T+c_3*H+c_4*T*H+c_5*T*T+c_6*H*H+c_7*T*T*H+c_8*T*H*H+c_9*T*T*H*H
 
    return heat_index
end


function calc_wind_chill(temperature, wind_speed)
  if temperature > 10 then
    log('temperature should be less than +10.0 Celsius degree')
      return -273
  end
   
  if wind_speed < 0 or wind_speed > 49.2 then
      log('wind speed should be in a range 0 ... 49.2 m/s')
    return -273
  end
 
  local T_air = temperature -- air temperature Celsius degree
 
  local a = 0.62 -- coef
  local b = 0.51 -- coef
  local T_1 = 13.1 -- Celsius degree
  local T_2 = 14.6 -- Celsius degree
 
  local M_0 = 1.3333 -- m/s
  local M = wind_speed -- m/s
 
  local T_wind_chill
 
  if M > M_0 then
    T_wind_chill = (a*T_air + T_1) + (b*T_air - T_2)*(M/M_0)^0.16
  else
    T_wind_chill = T_air
  end
 
  return T_wind_chill
end


function calc_feelslike(temperature, wind_speed, humidity)
  local T_feelslike
 
  if temperature <= 10.0 then -- if less than 10.0 Celsius degree (or equal) then wind chill
    T_feelslike = calc_wind_chill(temperature, wind_speed)
  elseif temperature >= 26.7 then -- if more than 26.7 Celsius degree (or equal) then heat index
    T_feelslike = calc_heat_index(temperature, humidity)
  else -- other cases just return temperature
    T_feelslike = temperature
  end

  return T_feelslike
end


min_max_today = init_min_max_table() -- table for minimum maximum temperature, air pressure, wind direction
min_max_tomor = init_min_max_table() -- table for minimum maximum temperature, air pressure, wind direction

json = require('json')
http = require('socket.http')

args = 'lat=' .. latitude .. '&lon=' .. longitude

--url = 'https://api.met.no/weatherapi/locationforecast/2.0/compact?' .. args
url = 'https://api.met.no/weatherapi/locationforecast/2.0/complete?' .. args

mac = 0
io.readfile('/sys/class/net/eth0/address'):gsub('%x%x', function(v)
  mac = mac * 256 + tonumber(v, 16)
end)
http.USERAGENT = 'LM ' .. mac

res, err = http.request(url)
data = json.pdecode(res)


if type(data) == 'table' then
  timestamp, hour = set_timestamp(0) -- current day
 
  if hour < 10 then
    timestamp_current_hour = timestamp .. 'T0' .. hour .. ':00:00Z' -- time stamp for current hour
  else
    timestamp_current_hour = timestamp .. 'T' .. hour .. ':00:00Z'  -- time stamp for current hour
  end
 
  --log('timestamp = ' .. timestamp)
 
  timestamp_next = set_timestamp(1) -- timestamp for tomorrow
  --log('timestamp_next = ' .. timestamp_next)
 
  --timestamp_after_next = set_timestamp(2) -- timestamp for day after tomorrow
  --log('timestamp_after_next = ' .. timestamp_after_next)
 
  --timestamp_after_after = set_timestamp(3) -- timestamp for day after day after tomorrow
  --log('timestamp_after_after = ' .. timestamp_after_after)
 
  for i, entry in ipairs(data.properties.timeseries) do 
   
    -- for weather now
    if entry.time == timestamp_current_hour then -- get data only for one hour (current hour)
      current_data = entry.data.instant.details
      if type(current_data) == 'table' then
        temperature_YR = current_data.air_temperature or -273           -- temperature in Celsius degree
        air_pressure_YR = current_data.air_pressure_at_sea_level or -1  -- air pressure in hPa
        humidity_YR = current_data.relative_humidity or -1              -- air humidity in %
        wind_direction_YR = current_data.wind_from_direction or -1      -- wind direction in degrees [0;360)
        wind_speed_YR = current_data.wind_speed or -1                   -- wind speed in m/s
        uv_index_YR = current_data.ultraviolet_index_clear_sky or -1    -- uv index
        feelslike_temp_YR = calc_feelslike(temperature_YR, wind_speed_YR, humidity_YR) -- feels like temperature in Celsius degree
      end
    end
   
    if entry.time:sub(1, #timestamp) == timestamp then -- checks remaining hours + 3 previous hours of current day
        current_data = entry.data.instant.details
      if type(current_data) == 'table' then
        min_max_today = min_max_temp_press_wind(current_data, min_max_today)
      end
     
      if rain_tod_YR == false then -- if detected rain does not check for rain
        rain_tod_YR = check_for_rain(entry.data.next_1_hours)
      end
     
      if snow_tod_YR == false then -- if detected snow does not check for snow
        snow_tod_YR = check_for_snow(entry.data.next_1_hours)
      end
    end
   
    if entry.time:sub(1, #timestamp_next) == timestamp_next then -- checks 24 hours of next day
      tomor_data = entry.data.instant.details
      if type(tomor_data) == 'table' then
        min_max_tomor = min_max_temp_press_wind(tomor_data, min_max_tomor)
      end
     
      if rain_tom_YR == false then -- if detected rain does not check for rain
        rain_tom_YR = check_for_rain(entry.data.next_1_hours)
      end
     
      if snow_tom_YR == false then -- if detected snow does not check for snow
        snow_tom_YR = check_for_snow(entry.data.next_1_hours)
      end
    end
 
  end

 
  -- data for current hour
  grp.write(status_temp, temperature_YR)
  grp.write(status_pressure, air_pressure_YR)
  grp.write(status_humidity, humidity_YR)
  grp.write(status_wind_direction, wind_direction_YR)
  grp.write(status_wind_speed, wind_speed_YR)
  grp.write(status_uv_index, uv_index_YR)
  grp.write(status_feelslike_temp, feelslike_temp_YR)
 
 
  -- data for today: rain, snow; min and max for temperature, pressure, wind
  grp.write(status_rain_today, rain_tod_YR)
  grp.write(status_snow_today, snow_tod_YR)
 
  grp.write(status_min_temp_today, min_max_today.min_t)
  grp.write(status_max_temp_today, min_max_today.max_t)
  grp.write(status_min_pressure_today, min_max_today.min_p)
  grp.write(status_max_pressure_today, min_max_today.max_p)
  grp.write(status_min_wind_speed_today, min_max_today.min_w)
  grp.write(status_max_wind_speed_today, min_max_today.max_w)
  grp.write(status_min_uv_today, min_max_today.min_uv)
  grp.write(status_max_uv_today, min_max_today.max_uv)
 
 
  -- data for tomorrow: rain, snow; min and max for temperature, pressure, wind
  grp.write(status_rain_tomor, rain_tom_YR)
  grp.write(status_snow_tomor, snow_tom_YR)
 
  grp.write(status_min_temp_tomor, min_max_tomor.min_t)
  grp.write(status_max_temp_tomor, min_max_tomor.max_t)
  grp.write(status_min_pressure_tomor, min_max_tomor.min_p)
  grp.write(status_max_pressure_tomor, min_max_tomor.max_p)
  grp.write(status_min_wind_speed_tomor, min_max_tomor.min_w)
  grp.write(status_max_wind_speed_tomor, min_max_tomor.max_w)
  grp.write(status_min_uv_tomor, min_max_tomor.min_uv)
  grp.write(status_max_uv_tomor, min_max_tomor.max_uv)
 
end

4. How often we can start this script?
You can run the script every four hours, should work fine.

Attached Files
.lua   my_script_v13.lua (Size: 15.57 KB / Downloads: 17)
Reply
#11
Thank you for the script RomansP!

Have tested, but I get no data coming to addresses 33/1/*. All stay at 0.
Although I receive a link with data when I log (url) at line 272.

Is it still working with you?
Reply
#12
Hi, Mrinj!

Yes it is still working for me. Can you attach your script, so I will try to figure out what could gone wrong.

The updated version for script.

Added check for http.request , so there will be a log if something gone wrong.

Code:
res, code = http.request(url)

if res and code == 200 then
  data = json.pdecode(res)
else
  log('request error', res, code)
end


Code:
-- Please comment objects which you are not using, comment also grp.write() at the bottom of script


--[[
-- You can set latitude and longitude in "Date time" option
-- go to LogicMachine->Utilities->Date and time

require('uci')

latitude = uci.get('genohm-scada.core.latitude') -- read latitude from system
latitude = tonumber(latitude) or 0

longitude = uci.get('genohm-scada.core.longitude') -- read longitude from system
longitude = tonumber(longitude) or 0

if(latitude == 0 and longitude == 0) then -- if cooridinates were not set in the system
  latitude = 51.5072 -- London
  longitude = 0.1276 -- London
end
--]]


-- you can set latitude and longitude manualy
-- (if you set coordinates using "Date time" do not forget to comment these two lines
latitude = 56.9496  -- Riga
longitude = 24.1052 -- Riga


--log('latitude = ' .. latitude)
--log('longitude = ' .. longitude)


--[[
status_temp = '32/1/13'           -- group address of temperature, should be float
status_pressure = '32/1/14'       -- air pressure, should be float
status_humidity = '32/1/15'       -- relative humidity, should be float
status_wind_direction = '32/1/16' -- wind direction, should be float
status_wind_speed = '32/1/17'     -- wind speed, should be float
status_uv_index = '32/2/4'        -- UV index, should be float
status_feelslike_temp = '32/2/3'  -- feels like temperature, should be float

status_rain_today = '32/1/11'     -- today's rain object, should be boolean
status_snow_today = '32/1/12'     -- today's snow object, should be boolean

status_min_temp_today = '32/1/20'       -- today's minimum air temperature, float
status_max_temp_today = '32/1/21'       -- today's maximum air temperature, float
status_min_pressure_today = '32/1/22'   -- minimum air pressure, float
status_max_pressure_today = '32/1/23'   -- maximum air pressure, float
status_min_wind_speed_today = '32/1/24' -- minimum wind speed, float
status_max_wind_speed_today = '32/1/25' -- maximum wind speed, float
status_min_uv_today = '32/2/5'          -- minimum UV today, float
status_max_uv_today = '32/2/6'          -- maximum UV today, float

status_rain_tomor = '32/1/9'   -- tomorrow's rain object
status_snow_tomor = '32/1/10'  -- tomorrow's snow object

status_min_temp_tomor = '32/1/26'
status_max_temp_tomor = '32/1/27'
status_min_pressure_tomor = '32/1/28'
status_max_pressure_tomor = '32/1/29'
status_min_wind_speed_tomor = '32/1/30'
status_max_wind_speed_tomor = '32/1/31'
status_min_uv_tomor = '32/2/7'
status_max_uv_tomor = '32/2/8'
--]]

--[[]]
status_temp = grp.create({ datatype = dt.float16, address = '33/1/1', name = 'current_temp',})
status_pressure = grp.create({ datatype = dt.uint16, address = '33/1/2', name = 'current_press',})
status_humidity = grp.create({ datatype = dt.scale, address = '33/1/3', name = 'current_humid',})
status_wind_direction = grp.create({ datatype = dt.float16, address = '33/1/4', name = 'current_wind_dir',})
status_wind_speed = grp.create({ datatype = dt.float16, address = '33/1/5', name = 'current_wind_sp',})
status_uv_index = grp.create({ datatype = dt.uint8, address = '33/1/6', name = 'current_uv_index',})
status_feelslike_temp = grp.create({ datatype = dt.float16, address = '33/1/7', name = 'current_feels_temp',})

status_rain_today = grp.create({ datatype = dt.bool, address = '33/1/8', name = 'rain_today',})
status_snow_today = grp.create({ datatype = dt.bool, address = '33/1/9', name = 'snow_today',})

status_min_temp_today = grp.create({ datatype = dt.float16, address = '33/1/10', name = 'today_temp_min',})
status_max_temp_today = grp.create({ datatype = dt.float16, address = '33/1/11', name = 'today_temp_max',})
status_min_pressure_today = grp.create({ datatype = dt.uint16, address = '33/1/12', name = 'today_press_min',})
status_max_pressure_today = grp.create({ datatype = dt.uint16, address = '33/1/13', name = 'today_press_max',})
status_min_wind_speed_today = grp.create({ datatype = dt.float16, address = '33/1/14', name = 'today_wind_min',})
status_max_wind_speed_today = grp.create({ datatype = dt.float16, address = '33/1/15', name = 'today_wind_max',})
status_min_uv_today = grp.create({ datatype = dt.uint8, address = '33/1/16', name = 'today_uv_min',})
status_max_uv_today = grp.create({ datatype = dt.uint8, address = '33/1/17', name = 'today_uv_max',})

status_rain_tomor = grp.create({ datatype = dt.bool, address = '33/1/18', name = 'rain_tomor',})
status_snow_tomor = grp.create({ datatype = dt.bool, address = '33/1/19', name = 'snow_tomor',})

status_min_temp_tomor = grp.create({ datatype = dt.float16, address = '33/1/20', name = 'tomor_temp_min',})
status_max_temp_tomor = grp.create({ datatype = dt.float16, address = '33/1/21', name = 'tomor_temp_max',})
status_min_pressure_tomor = grp.create({ datatype = dt.uint16, address = '33/1/22', name = 'tomor_press_min',})
status_max_pressure_tomor = grp.create({ datatype = dt.uint16, address = '33/1/23', name = 'tomor_press_max',})
status_min_wind_speed_tomor = grp.create({ datatype = dt.float16, address = '33/1/24', name = 'tomor_wind_min',})
status_max_wind_speed_tomor = grp.create({ datatype = dt.float16, address = '33/1/25', name = 'tomor_wind_max',})
status_min_uv_tomor = grp.create({ datatype = dt.uint8, address = '33/1/26', name = 'tomor_uv_min',})
status_max_uv_tomor = grp.create({ datatype = dt.uint8, address = '33/1/27', name = 'tomor_uv_max',})
--]]

rain_tod_YR = false        -- is rainy or not (for today)
snow_tod_YR = false        -- is snowy or not (for today)
rain_tom_YR = false        -- is rainy or not (for tomorrow)
snow_tom_YR = false        -- is snowy or not (for tomorrow)

-- current temperature, air pressure, humidity, wind direction and speed
temperature_YR = -273    -- temperature in degree Celsius
air_pressure_YR = -1     -- air pressure in hPa
humidity_YR = -1         -- air humidity in %
wind_direction_YR = -1   -- wind direction in degrees [0; 360)
wind_speed_YR = -1       -- wind speed in m/s
uv_index_YR = -1         -- UV index
feelslike_temp_YR = -273 -- feels like temperature in degree Celsius


function init_min_max_table() -- initialize table for minimum, maximum temperature, pressure, windspeed
  local min_max = {}
  min_max.min_t = 8000 -- minimum temperature for today
  min_max.max_t = -273 -- maximum temperature for today
  min_max.min_p = 8000 -- minimum pressure for today
  min_max.max_p = -1   -- maximum pressure for today
  min_max.min_w = 8000 -- minimum wind speed for today
  min_max.max_w = -1   -- maximum wind speed for today
  min_max.min_uv = 8000 -- minimum UV index
  min_max.max_uv = -1   -- maximum UV index
 
  return min_max
end


function set_timestamp(day) -- if day = 0 today; if day = 1 tomorrow, if day = 2 day after tomorrow
  local date = os.date('*t')
  date.day = date.day + day
  local time = os.time(date)
  return os.date('%Y-%m-%d', time), date.hour -- timestamp and current hour
end


-- minimum maximum values of temperature, pressure and windspeed
function min_max_temp_press_wind(dat_tab, min_max_tab)
  min_max_tab.min_t = math.min(min_max_tab.min_t, dat_tab.air_temperature or 8000)
  min_max_tab.max_t = math.max(min_max_tab.max_t, dat_tab.air_temperature or -273)
  min_max_tab.min_p = math.min(min_max_tab.min_p, dat_tab.air_pressure_at_sea_level or 8000)
  min_max_tab.max_p = math.max(min_max_tab.max_p, dat_tab.air_pressure_at_sea_level or -1)
  min_max_tab.min_w = math.min(min_max_tab.min_w, dat_tab.wind_speed or 8000)
  min_max_tab.max_w = math.max(min_max_tab.max_w, dat_tab.wind_speed or -1)
  min_max_tab.min_uv = math.min(min_max_tab.min_uv, dat_tab.ultraviolet_index_clear_sky or 8000)
  min_max_tab.max_uv = math.max(min_max_tab.max_uv, dat_tab.ultraviolet_index_clear_sky or -1)
 
  return min_max_tab
end


function check_for_rain(next1h)
  local is_rainy = false
  local code = ''
 
  if type(next1h) == 'table' and type(next1h.summary) == 'table' then
    code = next1h.summary.symbol_code or ''
  end
 
  if code:find('rain') then
    is_rainy = true
  end
 
  return is_rainy
end


function check_for_snow(next1h)
  local is_snowy = false
  local code = ''
 
  if type(next1h) == 'table' and type(next1h.summary) == 'table' then
    code = next1h.summary.symbol_code or ''
  end
 
  if code:find('snow') then
    is_snowy = true
  end

  return is_snowy
end


function calc_heat_index(temperature, humidity)
  if temperature < 26.7 then
    log('for heat_index calculation temperature should be higher than +26.7 Celsius degree')
    return -273
  end
 
  if humidity < 0 or humidity > 100 then
    log('humidity should be in a range from 0 ... 100%')
    return -273
  end
 
  local T = temperature
  local H = humidity
  local c_1 = -8.785
  local c_2 = 1.611
  local c_3 = 2.339
  local c_4 = -0.146
  local c_5 = -0.0123
  local c_6 = -0.0164
  local c_7 = 0.00221
  local c_8 = 0.000725
  local c_9 = -0.00000358
  local heat_index = c_1+c_2*T+c_3*H+c_4*T*H+c_5*T*T+c_6*H*H+c_7*T*T*H+c_8*T*H*H+c_9*T*T*H*H
 
    return heat_index
end


function calc_wind_chill(temperature, wind_speed)
  if temperature > 10 then
    log('temperature should be less than +10.0 Celsius degree')
      return -273
  end
   
  if wind_speed < 0 or wind_speed > 49.2 then
      log('wind speed should be in a range 0 ... 49.2 m/s')
    return -273
  end
 
  local T_air = temperature -- air temperature Celsius degree
 
  local a = 0.62 -- coef
  local b = 0.51 -- coef
  local T_1 = 13.1 -- Celsius degree
  local T_2 = 14.6 -- Celsius degree
 
  local M_0 = 1.3333 -- m/s
  local M = wind_speed -- m/s
 
  local T_wind_chill
 
  if M > M_0 then
    T_wind_chill = (a*T_air + T_1) + (b*T_air - T_2)*(M/M_0)^0.16
  else
    T_wind_chill = T_air
  end
 
  return T_wind_chill
end


function calc_feelslike(temperature, wind_speed, humidity)
  local T_feelslike
 
  if temperature <= 10.0 then -- if less than 10.0 Celsius degree (or equal) then wind chill
    T_feelslike = calc_wind_chill(temperature, wind_speed)
  elseif temperature >= 26.7 then -- if more than 26.7 Celsius degree (or equal) then heat index
    T_feelslike = calc_heat_index(temperature, humidity)
  else -- other cases just return temperature
    T_feelslike = temperature
  end

  return T_feelslike
end


min_max_today = init_min_max_table() -- table for minimum maximum temperature, air pressure, wind direction
min_max_tomor = init_min_max_table() -- table for minimum maximum temperature, air pressure, wind direction

json = require('json')
http = require('socket.http')

args = 'lat=' .. latitude .. '&lon=' .. longitude

--url = 'https://api.met.no/weatherapi/locationforecast/2.0/compact?' .. args
url = 'https://api.met.no/weatherapi/locationforecast/2.0/complete?' .. args

mac = 0
io.readfile('/sys/class/net/eth0/address'):gsub('%x%x', function(v)
  mac = mac * 256 + tonumber(v, 16)
end)
http.USERAGENT = 'LM ' .. mac

res, code = http.request(url)

if res and code == 200 then
  data = json.pdecode(res)
else
  log('request error', res, code)
end



if type(data) == 'table' then
  timestamp, hour = set_timestamp(0) -- current day
 
  if hour < 10 then
    timestamp_current_hour = timestamp .. 'T0' .. hour .. ':00:00Z' -- time stamp for current hour
  else
    timestamp_current_hour = timestamp .. 'T' .. hour .. ':00:00Z'  -- time stamp for current hour
  end
 
  --log('timestamp = ' .. timestamp)
 
  timestamp_next = set_timestamp(1) -- timestamp for tomorrow
  --log('timestamp_next = ' .. timestamp_next)
 
  --timestamp_after_next = set_timestamp(2) -- timestamp for day after tomorrow
  --log('timestamp_after_next = ' .. timestamp_after_next)
 
  --timestamp_after_after = set_timestamp(3) -- timestamp for day after day after tomorrow
  --log('timestamp_after_after = ' .. timestamp_after_after)
 
  for i, entry in ipairs(data.properties.timeseries) do 
   
    -- for weather now
    if entry.time == timestamp_current_hour then -- get data only for one hour (current hour)
      current_data = entry.data.instant.details
      if type(current_data) == 'table' then
        temperature_YR = current_data.air_temperature or -273           -- temperature in Celsius degree
        air_pressure_YR = current_data.air_pressure_at_sea_level or -1  -- air pressure in hPa
        humidity_YR = current_data.relative_humidity or -1              -- air humidity in %
        wind_direction_YR = current_data.wind_from_direction or -1      -- wind direction in degrees [0;360)
        wind_speed_YR = current_data.wind_speed or -1                   -- wind speed in m/s
        uv_index_YR = current_data.ultraviolet_index_clear_sky or -1    -- uv index
        feelslike_temp_YR = calc_feelslike(temperature_YR, wind_speed_YR, humidity_YR) -- feels like temperature in Celsius degree
      end
    end
   
    if entry.time:sub(1, #timestamp) == timestamp then -- checks remaining hours + 3 previous hours of current day
        current_data = entry.data.instant.details
      if type(current_data) == 'table' then
        min_max_today = min_max_temp_press_wind(current_data, min_max_today)
      end
     
      if rain_tod_YR == false then -- if detected rain does not check for rain
        rain_tod_YR = check_for_rain(entry.data.next_1_hours)
      end
     
      if snow_tod_YR == false then -- if detected snow does not check for snow
        snow_tod_YR = check_for_snow(entry.data.next_1_hours)
      end
    end
   
    if entry.time:sub(1, #timestamp_next) == timestamp_next then -- checks 24 hours of next day
      tomor_data = entry.data.instant.details
      if type(tomor_data) == 'table' then
        min_max_tomor = min_max_temp_press_wind(tomor_data, min_max_tomor)
      end
     
      if rain_tom_YR == false then -- if detected rain does not check for rain
        rain_tom_YR = check_for_rain(entry.data.next_1_hours)
      end
     
      if snow_tom_YR == false then -- if detected snow does not check for snow
        snow_tom_YR = check_for_snow(entry.data.next_1_hours)
      end
    end
 
  end

 
  -- data for current hour
  grp.write(status_temp, temperature_YR)
  grp.write(status_pressure, air_pressure_YR)
  grp.write(status_humidity, humidity_YR)
  grp.write(status_wind_direction, wind_direction_YR)
  grp.write(status_wind_speed, wind_speed_YR)
  grp.write(status_uv_index, uv_index_YR)
  grp.write(status_feelslike_temp, feelslike_temp_YR)
 
 
  -- data for today: rain, snow; min and max for temperature, pressure, wind
  grp.write(status_rain_today, rain_tod_YR)
  grp.write(status_snow_today, snow_tod_YR)
 
  grp.write(status_min_temp_today, min_max_today.min_t)
  grp.write(status_max_temp_today, min_max_today.max_t)
  grp.write(status_min_pressure_today, min_max_today.min_p)
  grp.write(status_max_pressure_today, min_max_today.max_p)
  grp.write(status_min_wind_speed_today, min_max_today.min_w)
  grp.write(status_max_wind_speed_today, min_max_today.max_w)
  grp.write(status_min_uv_today, min_max_today.min_uv)
  grp.write(status_max_uv_today, min_max_today.max_uv)
 
 
  -- data for tomorrow: rain, snow; min and max for temperature, pressure, wind
  grp.write(status_rain_tomor, rain_tom_YR)
  grp.write(status_snow_tomor, snow_tom_YR)
 
  grp.write(status_min_temp_tomor, min_max_tomor.min_t)
  grp.write(status_max_temp_tomor, min_max_tomor.max_t)
  grp.write(status_min_pressure_tomor, min_max_tomor.min_p)
  grp.write(status_max_pressure_tomor, min_max_tomor.max_p)
  grp.write(status_min_wind_speed_tomor, min_max_tomor.min_w)
  grp.write(status_max_wind_speed_tomor, min_max_tomor.max_w)
  grp.write(status_min_uv_tomor, min_max_tomor.min_uv)
  grp.write(status_max_uv_tomor, min_max_tomor.max_uv)
 
end

Attached Files
.lua   my_script_v14.lua (Size: 15.65 KB / Downloads: 15)
Reply
#13
(22.06.2022, 08:00)Mrinj Wrote: Thank you for the script RomansP!

Have tested, but I get no data coming to addresses 33/1/*. All stay at 0.
Although I receive a link with data when I log (url) at line 272.

Is it still working with you?

Great script, 

Thank you for sharing it.
Reply
#14
(22.06.2022, 08:17)Thank you RomansP! Very kind of you! Wrote: Testing with your V14 script I get the following error in the log:

-------------
* arg: 1
  * string: request error
* arg: 2
  * nil
* arg: 3
  * string: error:1409442E:lib(20):func(148):reason(1070)
-------------

As sad earlier, from your script I only change the addresses to 53/1/* from your script cause my 33/*/* once are busy Smile
Script is attached.

Thanks!

BR,
Mrinj



RomansPHi, Mrinj!

Yes it is still working for me. Can you attach your script, so I will try to figure out what could gone wrong.

The updated version for script.

Added check for http.request , so there will be a log if something gone wrong.

Code:
res, code = http.request(url)

if res and code == 200 then
  data = json.pdecode(res)
else
  log('request error', res, code)
end


Code:
-- Please comment objects which you are not using, comment also grp.write() at the bottom of script


--[[
-- You can set latitude and longitude in "Date time" option
-- go to LogicMachine->Utilities->Date and time

require('uci')

latitude = uci.get('genohm-scada.core.latitude') -- read latitude from system
latitude = tonumber(latitude) or 0

longitude = uci.get('genohm-scada.core.longitude') -- read longitude from system
longitude = tonumber(longitude) or 0

if(latitude == 0 and longitude == 0) then -- if cooridinates were not set in the system
  latitude = 51.5072 -- London
  longitude = 0.1276 -- London
end
--]]


-- you can set latitude and longitude manualy
-- (if you set coordinates using "Date time" do not forget to comment these two lines
latitude = 56.9496  -- Riga
longitude = 24.1052 -- Riga


--log('latitude = ' .. latitude)
--log('longitude = ' .. longitude)


--[[
status_temp = '32/1/13'           -- group address of temperature, should be float
status_pressure = '32/1/14'       -- air pressure, should be float
status_humidity = '32/1/15'       -- relative humidity, should be float
status_wind_direction = '32/1/16' -- wind direction, should be float
status_wind_speed = '32/1/17'     -- wind speed, should be float
status_uv_index = '32/2/4'        -- UV index, should be float
status_feelslike_temp = '32/2/3'  -- feels like temperature, should be float

status_rain_today = '32/1/11'     -- today's rain object, should be boolean
status_snow_today = '32/1/12'     -- today's snow object, should be boolean

status_min_temp_today = '32/1/20'       -- today's minimum air temperature, float
status_max_temp_today = '32/1/21'       -- today's maximum air temperature, float
status_min_pressure_today = '32/1/22'   -- minimum air pressure, float
status_max_pressure_today = '32/1/23'   -- maximum air pressure, float
status_min_wind_speed_today = '32/1/24' -- minimum wind speed, float
status_max_wind_speed_today = '32/1/25' -- maximum wind speed, float
status_min_uv_today = '32/2/5'          -- minimum UV today, float
status_max_uv_today = '32/2/6'          -- maximum UV today, float

status_rain_tomor = '32/1/9'   -- tomorrow's rain object
status_snow_tomor = '32/1/10'  -- tomorrow's snow object

status_min_temp_tomor = '32/1/26'
status_max_temp_tomor = '32/1/27'
status_min_pressure_tomor = '32/1/28'
status_max_pressure_tomor = '32/1/29'
status_min_wind_speed_tomor = '32/1/30'
status_max_wind_speed_tomor = '32/1/31'
status_min_uv_tomor = '32/2/7'
status_max_uv_tomor = '32/2/8'
--]]

--[[]]
status_temp = grp.create({ datatype = dt.float16, address = '33/1/1', name = 'current_temp',})
status_pressure = grp.create({ datatype = dt.uint16, address = '33/1/2', name = 'current_press',})
status_humidity = grp.create({ datatype = dt.scale, address = '33/1/3', name = 'current_humid',})
status_wind_direction = grp.create({ datatype = dt.float16, address = '33/1/4', name = 'current_wind_dir',})
status_wind_speed = grp.create({ datatype = dt.float16, address = '33/1/5', name = 'current_wind_sp',})
status_uv_index = grp.create({ datatype = dt.uint8, address = '33/1/6', name = 'current_uv_index',})
status_feelslike_temp = grp.create({ datatype = dt.float16, address = '33/1/7', name = 'current_feels_temp',})

status_rain_today = grp.create({ datatype = dt.bool, address = '33/1/8', name = 'rain_today',})
status_snow_today = grp.create({ datatype = dt.bool, address = '33/1/9', name = 'snow_today',})

status_min_temp_today = grp.create({ datatype = dt.float16, address = '33/1/10', name = 'today_temp_min',})
status_max_temp_today = grp.create({ datatype = dt.float16, address = '33/1/11', name = 'today_temp_max',})
status_min_pressure_today = grp.create({ datatype = dt.uint16, address = '33/1/12', name = 'today_press_min',})
status_max_pressure_today = grp.create({ datatype = dt.uint16, address = '33/1/13', name = 'today_press_max',})
status_min_wind_speed_today = grp.create({ datatype = dt.float16, address = '33/1/14', name = 'today_wind_min',})
status_max_wind_speed_today = grp.create({ datatype = dt.float16, address = '33/1/15', name = 'today_wind_max',})
status_min_uv_today = grp.create({ datatype = dt.uint8, address = '33/1/16', name = 'today_uv_min',})
status_max_uv_today = grp.create({ datatype = dt.uint8, address = '33/1/17', name = 'today_uv_max',})

status_rain_tomor = grp.create({ datatype = dt.bool, address = '33/1/18', name = 'rain_tomor',})
status_snow_tomor = grp.create({ datatype = dt.bool, address = '33/1/19', name = 'snow_tomor',})

status_min_temp_tomor = grp.create({ datatype = dt.float16, address = '33/1/20', name = 'tomor_temp_min',})
status_max_temp_tomor = grp.create({ datatype = dt.float16, address = '33/1/21', name = 'tomor_temp_max',})
status_min_pressure_tomor = grp.create({ datatype = dt.uint16, address = '33/1/22', name = 'tomor_press_min',})
status_max_pressure_tomor = grp.create({ datatype = dt.uint16, address = '33/1/23', name = 'tomor_press_max',})
status_min_wind_speed_tomor = grp.create({ datatype = dt.float16, address = '33/1/24', name = 'tomor_wind_min',})
status_max_wind_speed_tomor = grp.create({ datatype = dt.float16, address = '33/1/25', name = 'tomor_wind_max',})
status_min_uv_tomor = grp.create({ datatype = dt.uint8, address = '33/1/26', name = 'tomor_uv_min',})
status_max_uv_tomor = grp.create({ datatype = dt.uint8, address = '33/1/27', name = 'tomor_uv_max',})
--]]

rain_tod_YR = false        -- is rainy or not (for today)
snow_tod_YR = false        -- is snowy or not (for today)
rain_tom_YR = false        -- is rainy or not (for tomorrow)
snow_tom_YR = false        -- is snowy or not (for tomorrow)

-- current temperature, air pressure, humidity, wind direction and speed
temperature_YR = -273    -- temperature in degree Celsius
air_pressure_YR = -1     -- air pressure in hPa
humidity_YR = -1         -- air humidity in %
wind_direction_YR = -1   -- wind direction in degrees [0; 360)
wind_speed_YR = -1       -- wind speed in m/s
uv_index_YR = -1         -- UV index
feelslike_temp_YR = -273 -- feels like temperature in degree Celsius


function init_min_max_table() -- initialize table for minimum, maximum temperature, pressure, windspeed
  local min_max = {}
  min_max.min_t = 8000 -- minimum temperature for today
  min_max.max_t = -273 -- maximum temperature for today
  min_max.min_p = 8000 -- minimum pressure for today
  min_max.max_p = -1   -- maximum pressure for today
  min_max.min_w = 8000 -- minimum wind speed for today
  min_max.max_w = -1   -- maximum wind speed for today
  min_max.min_uv = 8000 -- minimum UV index
  min_max.max_uv = -1   -- maximum UV index
 
  return min_max
end


function set_timestamp(day) -- if day = 0 today; if day = 1 tomorrow, if day = 2 day after tomorrow
  local date = os.date('*t')
  date.day = date.day + day
  local time = os.time(date)
  return os.date('%Y-%m-%d', time), date.hour -- timestamp and current hour
end


-- minimum maximum values of temperature, pressure and windspeed
function min_max_temp_press_wind(dat_tab, min_max_tab)
  min_max_tab.min_t = math.min(min_max_tab.min_t, dat_tab.air_temperature or 8000)
  min_max_tab.max_t = math.max(min_max_tab.max_t, dat_tab.air_temperature or -273)
  min_max_tab.min_p = math.min(min_max_tab.min_p, dat_tab.air_pressure_at_sea_level or 8000)
  min_max_tab.max_p = math.max(min_max_tab.max_p, dat_tab.air_pressure_at_sea_level or -1)
  min_max_tab.min_w = math.min(min_max_tab.min_w, dat_tab.wind_speed or 8000)
  min_max_tab.max_w = math.max(min_max_tab.max_w, dat_tab.wind_speed or -1)
  min_max_tab.min_uv = math.min(min_max_tab.min_uv, dat_tab.ultraviolet_index_clear_sky or 8000)
  min_max_tab.max_uv = math.max(min_max_tab.max_uv, dat_tab.ultraviolet_index_clear_sky or -1)
 
  return min_max_tab
end


function check_for_rain(next1h)
  local is_rainy = false
  local code = ''
 
  if type(next1h) == 'table' and type(next1h.summary) == 'table' then
    code = next1h.summary.symbol_code or ''
  end
 
  if code:find('rain') then
    is_rainy = true
  end
 
  return is_rainy
end


function check_for_snow(next1h)
  local is_snowy = false
  local code = ''
 
  if type(next1h) == 'table' and type(next1h.summary) == 'table' then
    code = next1h.summary.symbol_code or ''
  end
 
  if code:find('snow') then
    is_snowy = true
  end

  return is_snowy
end


function calc_heat_index(temperature, humidity)
  if temperature < 26.7 then
    log('for heat_index calculation temperature should be higher than +26.7 Celsius degree')
    return -273
  end
 
  if humidity < 0 or humidity > 100 then
    log('humidity should be in a range from 0 ... 100%')
    return -273
  end
 
  local T = temperature
  local H = humidity
  local c_1 = -8.785
  local c_2 = 1.611
  local c_3 = 2.339
  local c_4 = -0.146
  local c_5 = -0.0123
  local c_6 = -0.0164
  local c_7 = 0.00221
  local c_8 = 0.000725
  local c_9 = -0.00000358
  local heat_index = c_1+c_2*T+c_3*H+c_4*T*H+c_5*T*T+c_6*H*H+c_7*T*T*H+c_8*T*H*H+c_9*T*T*H*H
 
    return heat_index
end


function calc_wind_chill(temperature, wind_speed)
  if temperature > 10 then
    log('temperature should be less than +10.0 Celsius degree')
      return -273
  end
   
  if wind_speed < 0 or wind_speed > 49.2 then
      log('wind speed should be in a range 0 ... 49.2 m/s')
    return -273
  end
 
  local T_air = temperature -- air temperature Celsius degree
 
  local a = 0.62 -- coef
  local b = 0.51 -- coef
  local T_1 = 13.1 -- Celsius degree
  local T_2 = 14.6 -- Celsius degree
 
  local M_0 = 1.3333 -- m/s
  local M = wind_speed -- m/s
 
  local T_wind_chill
 
  if M > M_0 then
    T_wind_chill = (a*T_air + T_1) + (b*T_air - T_2)*(M/M_0)^0.16
  else
    T_wind_chill = T_air
  end
 
  return T_wind_chill
end


function calc_feelslike(temperature, wind_speed, humidity)
  local T_feelslike
 
  if temperature <= 10.0 then -- if less than 10.0 Celsius degree (or equal) then wind chill
    T_feelslike = calc_wind_chill(temperature, wind_speed)
  elseif temperature >= 26.7 then -- if more than 26.7 Celsius degree (or equal) then heat index
    T_feelslike = calc_heat_index(temperature, humidity)
  else -- other cases just return temperature
    T_feelslike = temperature
  end

  return T_feelslike
end


min_max_today = init_min_max_table() -- table for minimum maximum temperature, air pressure, wind direction
min_max_tomor = init_min_max_table() -- table for minimum maximum temperature, air pressure, wind direction

json = require('json')
http = require('socket.http')

args = 'lat=' .. latitude .. '&lon=' .. longitude

--url = 'https://api.met.no/weatherapi/locationforecast/2.0/compact?' .. args
url = 'https://api.met.no/weatherapi/locationforecast/2.0/complete?' .. args

mac = 0
io.readfile('/sys/class/net/eth0/address'):gsub('%x%x', function(v)
  mac = mac * 256 + tonumber(v, 16)
end)
http.USERAGENT = 'LM ' .. mac

res, code = http.request(url)

if res and code == 200 then
  data = json.pdecode(res)
else
  log('request error', res, code)
end



if type(data) == 'table' then
  timestamp, hour = set_timestamp(0) -- current day
 
  if hour < 10 then
    timestamp_current_hour = timestamp .. 'T0' .. hour .. ':00:00Z' -- time stamp for current hour
  else
    timestamp_current_hour = timestamp .. 'T' .. hour .. ':00:00Z'  -- time stamp for current hour
  end
 
  --log('timestamp = ' .. timestamp)
 
  timestamp_next = set_timestamp(1) -- timestamp for tomorrow
  --log('timestamp_next = ' .. timestamp_next)
 
  --timestamp_after_next = set_timestamp(2) -- timestamp for day after tomorrow
  --log('timestamp_after_next = ' .. timestamp_after_next)
 
  --timestamp_after_after = set_timestamp(3) -- timestamp for day after day after tomorrow
  --log('timestamp_after_after = ' .. timestamp_after_after)
 
  for i, entry in ipairs(data.properties.timeseries) do 
   
    -- for weather now
    if entry.time == timestamp_current_hour then -- get data only for one hour (current hour)
      current_data = entry.data.instant.details
      if type(current_data) == 'table' then
        temperature_YR = current_data.air_temperature or -273           -- temperature in Celsius degree
        air_pressure_YR = current_data.air_pressure_at_sea_level or -1  -- air pressure in hPa
        humidity_YR = current_data.relative_humidity or -1              -- air humidity in %
        wind_direction_YR = current_data.wind_from_direction or -1      -- wind direction in degrees [0;360)
        wind_speed_YR = current_data.wind_speed or -1                   -- wind speed in m/s
        uv_index_YR = current_data.ultraviolet_index_clear_sky or -1    -- uv index
        feelslike_temp_YR = calc_feelslike(temperature_YR, wind_speed_YR, humidity_YR) -- feels like temperature in Celsius degree
      end
    end
   
    if entry.time:sub(1, #timestamp) == timestamp then -- checks remaining hours + 3 previous hours of current day
        current_data = entry.data.instant.details
      if type(current_data) == 'table' then
        min_max_today = min_max_temp_press_wind(current_data, min_max_today)
      end
     
      if rain_tod_YR == false then -- if detected rain does not check for rain
        rain_tod_YR = check_for_rain(entry.data.next_1_hours)
      end
     
      if snow_tod_YR == false then -- if detected snow does not check for snow
        snow_tod_YR = check_for_snow(entry.data.next_1_hours)
      end
    end
   
    if entry.time:sub(1, #timestamp_next) == timestamp_next then -- checks 24 hours of next day
      tomor_data = entry.data.instant.details
      if type(tomor_data) == 'table' then
        min_max_tomor = min_max_temp_press_wind(tomor_data, min_max_tomor)
      end
     
      if rain_tom_YR == false then -- if detected rain does not check for rain
        rain_tom_YR = check_for_rain(entry.data.next_1_hours)
      end
     
      if snow_tom_YR == false then -- if detected snow does not check for snow
        snow_tom_YR = check_for_snow(entry.data.next_1_hours)
      end
    end
 
  end

 
  -- data for current hour
  grp.write(status_temp, temperature_YR)
  grp.write(status_pressure, air_pressure_YR)
  grp.write(status_humidity, humidity_YR)
  grp.write(status_wind_direction, wind_direction_YR)
  grp.write(status_wind_speed, wind_speed_YR)
  grp.write(status_uv_index, uv_index_YR)
  grp.write(status_feelslike_temp, feelslike_temp_YR)
 
 
  -- data for today: rain, snow; min and max for temperature, pressure, wind
  grp.write(status_rain_today, rain_tod_YR)
  grp.write(status_snow_today, snow_tod_YR)
 
  grp.write(status_min_temp_today, min_max_today.min_t)
  grp.write(status_max_temp_today, min_max_today.max_t)
  grp.write(status_min_pressure_today, min_max_today.min_p)
  grp.write(status_max_pressure_today, min_max_today.max_p)
  grp.write(status_min_wind_speed_today, min_max_today.min_w)
  grp.write(status_max_wind_speed_today, min_max_today.max_w)
  grp.write(status_min_uv_today, min_max_today.min_uv)
  grp.write(status_max_uv_today, min_max_today.max_uv)
 
 
  -- data for tomorrow: rain, snow; min and max for temperature, pressure, wind
  grp.write(status_rain_tomor, rain_tom_YR)
  grp.write(status_snow_tomor, snow_tom_YR)
 
  grp.write(status_min_temp_tomor, min_max_tomor.min_t)
  grp.write(status_max_temp_tomor, min_max_tomor.max_t)
  grp.write(status_min_pressure_tomor, min_max_tomor.min_p)
  grp.write(status_max_pressure_tomor, min_max_tomor.max_p)
  grp.write(status_min_wind_speed_tomor, min_max_tomor.min_w)
  grp.write(status_max_wind_speed_tomor, min_max_tomor.max_w)
  grp.write(status_min_uv_tomor, min_max_tomor.min_uv)
  grp.write(status_max_uv_tomor, min_max_tomor.max_uv)
 
end

Attached Files
.lua   my_script_mrinj_v14.lua (Size: 15.65 KB / Downloads: 15)
Reply
#15
This lib/func/reason error is due to an outdated firmware.
Reply
#16
(23.06.2022, 06:24)admin Wrote: This lib/func/reason error is due to an outdated firmware.

Thank you admin!
I will update and test Smile
Reply
#17
Hello,
Please, I hope you could help me in my issue
However, Until now i had script work fine , but now i cant obtain weather dates,

This is the scheduled script that I used.
I can see on log :
* arg: 1
* string: <html>
<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<center>The plain HTTP request was sent to HTTPS port</center>
<hr><center>nginx/1.18.0 (Ubuntu)</center>
</body>
</html>

Code:
latitude = 40.4538899
longitude = -3.6211718

json = require('json')
http2 = require('socket.http')
log (http2)
--http = require('ssl.https')
--log ( http)
args = 'lat=' .. latitude .. '&lon=' .. longitude
url = 'https://api.met.no/weatherapi/locationforecast/2.0/compact?' .. args
--url = 'https://api.met.no/weatherapi/locationforecast/2.0/complete?' .. args
mac = 0
io.readfile('/sys/class/net/eth0/address'):gsub('%x%x', function(v)
  mac = mac * 256 + tonumber(v, 16)
end)
http2.USERAGENT = 'LM ' .. mac


res, err = http2.request(url)

log ( res, err)


data = json.pdecode(res)
log (data)
if type(data) == 'table' then
  date = os.date('*t')
  date.day = date.day + 1
  time = os.time(date)
  timestamp = os.date('%Y-%m-%d', time)
  log(data)
Reply
#18
You have an old firmware which does not support HTTPS directly in socket.http. ssl.https must be used instead.

The request part can be rewritten like this to work with older firmware:
Code:
latitude = 40.4538899
longitude = -3.6211718

https = require('ssl.https')
json = require('json')
ltn12 = require('ltn12')

args = 'lat=' .. latitude .. '&lon=' .. longitude

url = 'https://api.met.no/weatherapi/locationforecast/2.0/compact?' .. args

mac = 0
io.readfile('/sys/class/net/eth0/address'):gsub('%x%x', function(v)
  mac = mac * 256 + tonumber(v, 16)
end)

response = {}

res, code = https.request({
  url = url,
  protocol = 'tlsv12',
  headers = {
    ['user-agent'] = 'LM ' .. mac
  },
  sink = ltn12.sink.table(response)
})

if res and code == 200 then
  data = json.pdecode(table.concat(response))
end

if type(data) == 'table' then
  log(data)
else
  log('request failed', res, code)
end
Reply
#19
Thaks a lot!!
If I use the script above , I have no data , I receive :
table:
[data]
* table:
[next_6_hours]
* table:
[summary]
* table:
nesting too deep
[details]
* table:
nesting too deep
[next_12_hours]
* table:
[summary]
* table:
nesting too deep
[next_1_hours]
* table:
[summary]
* table:
nesting too deep
Reply
#20
Hi, Acla, it is correct, you need to parse all the data. You can use this script.

Code:
status_temp = grp.create({ datatype = dt.float16, address = '33/1/1', name = 'current_temp',})
status_pressure = grp.create({ datatype = dt.uint16, address = '33/1/2', name = 'current_press',})
status_humidity = grp.create({ datatype = dt.scale, address = '33/1/3', name = 'current_humid',})
status_wind_direction = grp.create({ datatype = dt.float16, address = '33/1/4', name = 'current_wind_dir',})
status_wind_speed = grp.create({ datatype = dt.float16, address = '33/1/5', name = 'current_wind_sp',})
status_uv_index = grp.create({ datatype = dt.uint8, address = '33/1/6', name = 'current_uv_index',})
status_feelslike_temp = grp.create({ datatype = dt.float16, address = '33/1/7', name = 'current_feels_temp',})

status_rain_today = grp.create({ datatype = dt.bool, address = '33/1/8', name = 'rain_today',})
status_snow_today = grp.create({ datatype = dt.bool, address = '33/1/9', name = 'snow_today',})

status_min_temp_today = grp.create({ datatype = dt.float16, address = '33/1/10', name = 'today_temp_min',})
status_max_temp_today = grp.create({ datatype = dt.float16, address = '33/1/11', name = 'today_temp_max',})
status_min_pressure_today = grp.create({ datatype = dt.uint16, address = '33/1/12', name = 'today_press_min',})
status_max_pressure_today = grp.create({ datatype = dt.uint16, address = '33/1/13', name = 'today_press_max',})
status_min_wind_speed_today = grp.create({ datatype = dt.float16, address = '33/1/14', name = 'today_wind_min',})
status_max_wind_speed_today = grp.create({ datatype = dt.float16, address = '33/1/15', name = 'today_wind_max',})
status_min_uv_today = grp.create({ datatype = dt.uint8, address = '33/1/16', name = 'today_uv_min',})
status_max_uv_today = grp.create({ datatype = dt.uint8, address = '33/1/17', name = 'today_uv_max',})

status_rain_tomor = grp.create({ datatype = dt.bool, address = '33/1/18', name = 'rain_tomor',})
status_snow_tomor = grp.create({ datatype = dt.bool, address = '33/1/19', name = 'snow_tomor',})

status_min_temp_tomor = grp.create({ datatype = dt.float16, address = '33/1/20', name = 'tomor_temp_min',})
status_max_temp_tomor = grp.create({ datatype = dt.float16, address = '33/1/21', name = 'tomor_temp_max',})
status_min_pressure_tomor = grp.create({ datatype = dt.uint16, address = '33/1/22', name = 'tomor_press_min',})
status_max_pressure_tomor = grp.create({ datatype = dt.uint16, address = '33/1/23', name = 'tomor_press_max',})
status_min_wind_speed_tomor = grp.create({ datatype = dt.float16, address = '33/1/24', name = 'tomor_wind_min',})
status_max_wind_speed_tomor = grp.create({ datatype = dt.float16, address = '33/1/25', name = 'tomor_wind_max',})
status_min_uv_tomor = grp.create({ datatype = dt.uint8, address = '33/1/26', name = 'tomor_uv_min',})
status_max_uv_tomor = grp.create({ datatype = dt.uint8, address = '33/1/27', name = 'tomor_uv_max',})

rain_tod_YR = false        -- is rainy or not (for today)
snow_tod_YR = false        -- is snowy or not (for today)
rain_tom_YR = false        -- is rainy or not (for tomorrow)
snow_tom_YR = false        -- is snowy or not (for tomorrow)

-- current temperature, air pressure, humidity, wind direction and speed
temperature_YR = -273    -- temperature in degree Celsius
air_pressure_YR = -1     -- air pressure in hPa
humidity_YR = -1         -- air humidity in %
wind_direction_YR = -1   -- wind direction in degrees [0; 360)
wind_speed_YR = -1       -- wind speed in m/s
uv_index_YR = -1         -- UV index
feelslike_temp_YR = -273 -- feels like temperature in degree Celsius


function init_min_max_table() -- initialize table for minimum, maximum temperature, pressure, windspeed
  local min_max = {}
  min_max.min_t = 8000 -- minimum temperature for today
  min_max.max_t = -273 -- maximum temperature for today
  min_max.min_p = 8000 -- minimum pressure for today
  min_max.max_p = -1   -- maximum pressure for today
  min_max.min_w = 8000 -- minimum wind speed for today
  min_max.max_w = -1   -- maximum wind speed for today
  min_max.min_uv = 8000 -- minimum UV index
  min_max.max_uv = -1   -- maximum UV index
 
  return min_max
end


function set_timestamp(day) -- if day = 0 today; if day = 1 tomorrow, if day = 2 day after tomorrow
  local date = os.date('*t')
  date.day = date.day + day
  local time = os.time(date)
  return os.date('%Y-%m-%d', time), date.hour -- timestamp and current hour
end


-- minimum maximum values of temperature, pressure and windspeed
function min_max_temp_press_wind(dat_tab, min_max_tab)
  min_max_tab.min_t = math.min(min_max_tab.min_t, dat_tab.air_temperature or 8000)
  min_max_tab.max_t = math.max(min_max_tab.max_t, dat_tab.air_temperature or -273)
  min_max_tab.min_p = math.min(min_max_tab.min_p, dat_tab.air_pressure_at_sea_level or 8000)
  min_max_tab.max_p = math.max(min_max_tab.max_p, dat_tab.air_pressure_at_sea_level or -1)
  min_max_tab.min_w = math.min(min_max_tab.min_w, dat_tab.wind_speed or 8000)
  min_max_tab.max_w = math.max(min_max_tab.max_w, dat_tab.wind_speed or -1)
  min_max_tab.min_uv = math.min(min_max_tab.min_uv, dat_tab.ultraviolet_index_clear_sky or 8000)
  min_max_tab.max_uv = math.max(min_max_tab.max_uv, dat_tab.ultraviolet_index_clear_sky or -1)
 
  return min_max_tab
end


function check_for_rain(next1h)
  local is_rainy = false
  local code = ''
 
  if type(next1h) == 'table' and type(next1h.summary) == 'table' then
    code = next1h.summary.symbol_code or ''
  end
 
  if code:find('rain') then
    is_rainy = true
  end
 
  return is_rainy
end


function check_for_snow(next1h)
  local is_snowy = false
  local code = ''
 
  if type(next1h) == 'table' and type(next1h.summary) == 'table' then
    code = next1h.summary.symbol_code or ''
  end
 
  if code:find('snow') then
    is_snowy = true
  end

  return is_snowy
end


function calc_heat_index(temperature, humidity)
  if temperature < 26.7 then
    log('for heat_index calculation temperature should be higher than +26.7 Celsius degree')
    return -273
  end
 
  if humidity < 0 or humidity > 100 then
    log('humidity should be in a range from 0 ... 100%')
    return -273
  end
 
  local T = temperature
  local H = humidity
  local c_1 = -8.785
  local c_2 = 1.611
  local c_3 = 2.339
  local c_4 = -0.146
  local c_5 = -0.0123
  local c_6 = -0.0164
  local c_7 = 0.00221
  local c_8 = 0.000725
  local c_9 = -0.00000358
  local heat_index = c_1+c_2*T+c_3*H+c_4*T*H+c_5*T*T+c_6*H*H+c_7*T*T*H+c_8*T*H*H+c_9*T*T*H*H
 
    return heat_index
end


function calc_wind_chill(temperature, wind_speed)
  if temperature > 10 then
    log('temperature should be less than +10.0 Celsius degree')
      return -273
  end
   
  if wind_speed < 0 or wind_speed > 49.2 then
      log('wind speed should be in a range 0 ... 49.2 m/s')
    return -273
  end
 
  local T_air = temperature -- air temperature Celsius degree
 
  local a = 0.62 -- coef
  local b = 0.51 -- coef
  local T_1 = 13.1 -- Celsius degree
  local T_2 = 14.6 -- Celsius degree
 
  local M_0 = 1.3333 -- m/s
  local M = wind_speed -- m/s
 
  local T_wind_chill
 
  if M > M_0 then
    T_wind_chill = (a*T_air + T_1) + (b*T_air - T_2)*(M/M_0)^0.16
  else
    T_wind_chill = T_air
  end
 
  return T_wind_chill
end


function calc_feelslike(temperature, wind_speed, humidity)
  local T_feelslike
 
  if temperature <= 10.0 then -- if less than 10.0 Celsius degree (or equal) then wind chill
    T_feelslike = calc_wind_chill(temperature, wind_speed)
  elseif temperature >= 26.7 then -- if more than 26.7 Celsius degree (or equal) then heat index
    T_feelslike = calc_heat_index(temperature, humidity)
  else -- other cases just return temperature
    T_feelslike = temperature
  end

  return T_feelslike
end


min_max_today = init_min_max_table() -- table for minimum maximum temperature, air pressure, wind direction
min_max_tomor = init_min_max_table() -- table for minimum maximum temperature, air pressure, wind direction

latitude = 40.4538899
longitude = -3.6211718

https = require('ssl.https')
json = require('json')
ltn12 = require('ltn12')

args = 'lat=' .. latitude .. '&lon=' .. longitude

url = 'https://api.met.no/weatherapi/locationforecast/2.0/complete?' .. args

mac = 0
io.readfile('/sys/class/net/eth0/address'):gsub('%x%x', function(v)
  mac = mac * 256 + tonumber(v, 16)
end)

response = {}

res, code = https.request({
  url = url,
  protocol = 'tlsv12',
  headers = {
    ['user-agent'] = 'LM ' .. mac
  },
  sink = ltn12.sink.table(response)
})


if res and code == 200 then
  data = json.pdecode(table.concat(response))
else
  log('request error', res, code)
end


if type(data) == 'table' then
  timestamp, hour = set_timestamp(0) -- current day
 
  if hour < 10 then
    timestamp_current_hour = timestamp .. 'T0' .. hour .. ':00:00Z' -- time stamp for current hour
  else
    timestamp_current_hour = timestamp .. 'T' .. hour .. ':00:00Z'  -- time stamp for current hour
  end
 
  --log('timestamp = ' .. timestamp)
 
  timestamp_next = set_timestamp(1) -- timestamp for tomorrow
  --log('timestamp_next = ' .. timestamp_next)
 
  --timestamp_after_next = set_timestamp(2) -- timestamp for day after tomorrow
  --log('timestamp_after_next = ' .. timestamp_after_next)
 
  --timestamp_after_after = set_timestamp(3) -- timestamp for day after day after tomorrow
  --log('timestamp_after_after = ' .. timestamp_after_after)
 
  for i, entry in ipairs(data.properties.timeseries) do 
   
    -- for weather now
    if entry.time == timestamp_current_hour then -- get data only for one hour (current hour)
      current_data = entry.data.instant.details
      if type(current_data) == 'table' then
        temperature_YR = current_data.air_temperature or -273           -- temperature in Celsius degree
        air_pressure_YR = current_data.air_pressure_at_sea_level or -1  -- air pressure in hPa
        humidity_YR = current_data.relative_humidity or -1              -- air humidity in %
        wind_direction_YR = current_data.wind_from_direction or -1      -- wind direction in degrees [0;360)
        wind_speed_YR = current_data.wind_speed or -1                   -- wind speed in m/s
        uv_index_YR = current_data.ultraviolet_index_clear_sky or -1    -- uv index
        feelslike_temp_YR = calc_feelslike(temperature_YR, wind_speed_YR, humidity_YR) -- feels like temperature in Celsius degree
      end
    end
   
    if entry.time:sub(1, #timestamp) == timestamp then -- checks remaining hours + 3 previous hours of current day
        current_data = entry.data.instant.details
      if type(current_data) == 'table' then
        min_max_today = min_max_temp_press_wind(current_data, min_max_today)
      end
     
      if rain_tod_YR == false then -- if detected rain does not check for rain
        rain_tod_YR = check_for_rain(entry.data.next_1_hours)
      end
     
      if snow_tod_YR == false then -- if detected snow does not check for snow
        snow_tod_YR = check_for_snow(entry.data.next_1_hours)
      end
    end
   
    if entry.time:sub(1, #timestamp_next) == timestamp_next then -- checks 24 hours of next day
      tomor_data = entry.data.instant.details
      if type(tomor_data) == 'table' then
        min_max_tomor = min_max_temp_press_wind(tomor_data, min_max_tomor)
      end
     
      if rain_tom_YR == false then -- if detected rain does not check for rain
        rain_tom_YR = check_for_rain(entry.data.next_1_hours)
      end
     
      if snow_tom_YR == false then -- if detected snow does not check for snow
        snow_tom_YR = check_for_snow(entry.data.next_1_hours)
      end
    end
 
  end

 
  -- data for current hour
  grp.write(status_temp, temperature_YR)
  grp.write(status_pressure, air_pressure_YR)
  grp.write(status_humidity, humidity_YR)
  grp.write(status_wind_direction, wind_direction_YR)
  grp.write(status_wind_speed, wind_speed_YR)
  grp.write(status_uv_index, uv_index_YR)
  grp.write(status_feelslike_temp, feelslike_temp_YR)
 
 
  -- data for today: rain, snow; min and max for temperature, pressure, wind
  grp.write(status_rain_today, rain_tod_YR)
  grp.write(status_snow_today, snow_tod_YR)
 
  grp.write(status_min_temp_today, min_max_today.min_t)
  grp.write(status_max_temp_today, min_max_today.max_t)
  grp.write(status_min_pressure_today, min_max_today.min_p)
  grp.write(status_max_pressure_today, min_max_today.max_p)
  grp.write(status_min_wind_speed_today, min_max_today.min_w)
  grp.write(status_max_wind_speed_today, min_max_today.max_w)
  grp.write(status_min_uv_today, min_max_today.min_uv)
  grp.write(status_max_uv_today, min_max_today.max_uv)
 
 
  -- data for tomorrow: rain, snow; min and max for temperature, pressure, wind
  grp.write(status_rain_tomor, rain_tom_YR)
  grp.write(status_snow_tomor, snow_tom_YR)
 
  grp.write(status_min_temp_tomor, min_max_tomor.min_t)
  grp.write(status_max_temp_tomor, min_max_tomor.max_t)
  grp.write(status_min_pressure_tomor, min_max_tomor.min_p)
  grp.write(status_max_pressure_tomor, min_max_tomor.max_p)
  grp.write(status_min_wind_speed_tomor, min_max_tomor.min_w)
  grp.write(status_max_wind_speed_tomor, min_max_tomor.max_w)
  grp.write(status_min_uv_tomor, min_max_tomor.min_uv)
  grp.write(status_max_uv_tomor, min_max_tomor.max_uv)
 
end
Reply


Forum Jump: