From 0e5e619625f49d92daa80b1ff316c0b0bd82ff31 Mon Sep 17 00:00:00 2001 From: xbgmsharp Date: Mon, 5 Feb 2024 12:51:43 +0100 Subject: [PATCH] Add cron process windy, send observations to windy station --- initdb/02_2_signalk_cron.sql | 90 +++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/initdb/02_2_signalk_cron.sql b/initdb/02_2_signalk_cron.sql index 67f1f9c..d3804a0 100644 --- a/initdb/02_2_signalk_cron.sql +++ b/initdb/02_2_signalk_cron.sql @@ -387,7 +387,7 @@ BEGIN PERFORM grafana_py_fn(data_rec.name, data_rec.vessel_id, data_rec.owner_email, app_settings); -- Gather user settings user_settings := get_user_settings_from_vesselid_fn(data_rec.vessel_id::TEXT); - RAISE DEBUG '-> DEBUG cron_process_grafana_fn get_user_settings_from_vesselid_fn [%]', user_settings; + --RAISE DEBUG '-> DEBUG cron_process_grafana_fn get_user_settings_from_vesselid_fn [%]', user_settings; -- add user in keycloak PERFORM keycloak_auth_py_fn(data_rec.vessel_id, user_settings, app_settings); -- Send notification @@ -406,6 +406,94 @@ COMMENT ON FUNCTION public.cron_process_grafana_fn IS 'init by pg_cron to check for new vessel pending grafana provisioning, if so perform grafana_py_fn'; +CREATE OR REPLACE FUNCTION public.cron_process_windy_fn() RETURNS void AS $$ +DECLARE + windy_rec record; + last_metric TIMESTAMPTZ; + metric_rec record; + windy_metric jsonb; + app_settings jsonb; + user_settings jsonb; + windy_pws jsonb; +BEGIN + -- Check for new observations pending update + RAISE NOTICE 'cron_process_windy_fn'; + -- Gather url from app settings + app_settings := get_app_settings_fn(); + -- Find users with windy active and with an active vessel + FOR windy_rec in + SELECT + a.id,a.user_id,a.email,v.vessel_id,m.name,COALESCE((a.preferences->'windy_last_metric')::TEXT,'2024-01-01') as last_metric + FROM auth.accounts a, auth.vessels v, api.metadata m + WHERE m.vessel_id = v.vessel_id + AND a.email = v.owner_email + AND (a.preferences->'public_windy')::boolean = True + AND m.active = true + LOOP + RAISE NOTICE '-> cron_process_windy_fn for [%]', windy_rec; + PERFORM set_config('vessel.id', windy_rec.vessel_id, false); + --RAISE WARNING 'public.cron_process_windy_rec_fn() scheduler vessel.id %, user.id', current_setting('vessel.id', false), current_setting('user.id', false); + -- Gather user settings + user_settings := get_user_settings_from_vesselid_fn(windy_rec.vessel_id::TEXT); + RAISE NOTICE '-> cron_process_windy_fn checking user_settings [%]', user_settings; + -- Get all metrics from the last windy_last_metric avg by 5 minutes + -- TODO json_agg to send all data in once, but issue with py jsonb transformation decimal. + FOR metric_rec in + SELECT time_bucket('5 minutes', m.time) AS time_bucket, + avg((m.metrics->'environment.outside.temperature')::numeric) AS temperature, + avg((m.metrics->'environment.outside.pressure')::numeric) AS pressure, + avg((m.metrics->'environment.outside.relativeHumidity')::numeric) AS rh, + avg((m.metrics->'environment.wind.directionTrue')::numeric) AS winddir, + avg((m.metrics->'environment.wind.speedOverGround')::numeric) AS wind, + max((m.metrics->'environment.wind.speedOverGround')::numeric) AS gust, + last(latitude, time) AS lat, + last(longitude, time) AS lng + FROM api.metrics m + WHERE vessel_id = windy_rec.vessel_id + AND m.time >= windy_rec.last_metric::TIMESTAMPTZ + GROUP BY time_bucket + ORDER BY time_bucket ASC LIMIT 100 + LOOP + RAISE NOTICE '-> cron_process_windy_fn checking metrics [%]', metric_rec; + -- https://community.windy.com/topic/8168/report-your-weather-station-data-to-windy + -- temp from kelvin to celcuis + -- winddir from radiant to degres + -- rh from ratio to percentage + SELECT jsonb_build_object( + 'dateutc', metric_rec.time_bucket, + 'station', windy_rec.id, + 'name', windy_rec.name, + 'lat', metric_rec.lat, + 'lon', metric_rec.lng, + 'wind', metric_rec.wind, + 'gust', metric_rec.gust, + 'pressure', metric_rec.pressure, + 'winddir', ROUND((((metric_rec.winddir)::numeric * 57.2958) * 10) / 10), + 'temp', ROUND((((metric_rec.temperature)::numeric - 273.15) * 10) / 10), + 'rh', ((metric_rec.rh)::numeric * 100) + ) INTO windy_metric; + RAISE NOTICE '-> cron_process_windy_fn checking windy_metrics [%]', windy_metric; + SELECT windy_pws_py_fn(windy_metric, user_settings, app_settings) into windy_pws; + RAISE NOTICE '-> cron_process_windy_fn Windy PWS [%]', ((windy_pws->'header')::JSONB ? 'id'); + IF NOT((user_settings->'settings')::JSONB ? 'windy') and ((windy_pws->'header')::JSONB ? 'id') then + RAISE NOTICE '-> cron_process_windy_fn new Windy PWS [%]', (windy_pws->'header')::JSONB->>'id'; + -- Send metrics to Windy + PERFORM api.update_user_preferences_fn('{windy}'::TEXT, ((windy_pws->'header')::JSONB->>'id')::TEXT); + -- Send notification + PERFORM send_notification_fn('windy'::TEXT, user_settings::JSONB); + END IF; + -- Record last metrics time + SELECT metric_rec.time_bucket INTO last_metric; + END LOOP; + PERFORM api.update_user_preferences_fn('{windy_last_metric}'::TEXT, last_metric::TEXT); + END LOOP; +END; +$$ language plpgsql; +-- Description +COMMENT ON FUNCTION + public.cron_process_windy_fn + IS 'init by pg_cron to create (or update) station and uploading observations to Windy Personal Weather Station observations'; + -- CRON for Vacuum database CREATE FUNCTION cron_vacuum_fn() RETURNS void AS $$ -- ERROR: VACUUM cannot be executed from a function