Just new here... do not know karen k, or about her repo yet... where is her repo is it on github? Yes AU is metric, I assume if you set the it in conf it will do what it does...
On Mon, 24 Mar 2025 at 16:08, 'michael.k...@gmx.at' via weewx-user < weewx-user@googlegroups.com> wrote: > Didn't Karen K have something of this sort in her repo? > > The above will only work with metric db, will it? > > Dr Henk Harms schrieb am Montag, 24. März 2025 um 06:56:39 UTC+1: > >> >> So been "messing with it" >> To create a table. >> >> CREATE TABLE archive_bom_minmax ( >> dateTime INTEGER NOT NULL PRIMARY KEY, >> usUnits INTEGER NOT NULL, >> `interval` INTEGER NOT NULL, >> min_temp DOUBLE, >> min_temp_time INTEGER, >> max_temp DOUBLE, >> max_temp_time INTEGER >> ); >> >> Then add this to /usr/share/weewx/user >> #!/usr/bin/env python >> # -*- coding: utf-8 -*- >> >> """ >> bom_minmax.py - WeeWX service to record BoM-compliant min/max temperatures >> >> This service records minimum and maximum temperatures between 6pm the >> previous >> day and 9am the current day, storing them at 9am in a dedicated table. >> """ >> >> import datetime >> import time >> import weedb >> import weewx >> from weewx.engine import StdService >> >> # Try to use new-style WeeWX V5 logging >> try: >> import logging >> log = logging.getLogger(__name__) >> def logdbg(msg): >> log.debug(msg) >> def loginf(msg): >> log.info(msg) >> def logerr(msg): >> log.error(msg) >> except (ImportError, AttributeError): >> # Use old-style WeeWX V4 logging via syslog >> import syslog >> def logmsg(level, msg): >> syslog.syslog(level, 'bom_minmax: %s' % msg) >> def logdbg(msg): >> logmsg(syslog.LOG_DEBUG, msg) >> def loginf(msg): >> logmsg(syslog.LOG_INFO, msg) >> def logerr(msg): >> logmsg(syslog.LOG_ERR, msg) >> >> # BoM observation time configuration >> BOM_MORNING_HOUR = 9 # 9am >> BOM_EVENING_HOUR = 18 # 6pm >> >> class BomMinMaxService(StdService): >> """Service to record min/max temperatures in BoM format.""" >> >> def __init__(self, engine, config_dict): >> super(BomMinMaxService, self).__init__(engine, config_dict) >> >> loginf("Starting BoM Min/Max Temperature Service") >> >> # Get the database configuration >> self.db_dict = config_dict.get('BomMinMax', {}) >> >> # Archive database binding - where to get temperature data from >> self.archive_binding = self.db_dict.get('archive_binding', >> 'wx_binding') >> >> # Output database binding - where to store BoM min/max data >> self.output_binding = self.db_dict.get('output_binding', >> 'wx_binding') >> >> # Table name for BoM min/max data >> self.table_name = self.db_dict.get('table_name', >> 'archive_bom_minmax') >> >> # Temperature field to use >> self.temp_field = self.db_dict.get('temp_field', 'outTemp') >> >> # Initialize the table if it doesn't exist >> # Commented out for stability >> #self.init_table() >> >> # Bind to archive events >> self.bind(weewx.NEW_ARCHIVE_RECORD, self.new_archive_record) >> >> loginf("BoM Min/Max Temperature Service initialized") >> >> def init_table(self): >> """Initialize the table if it doesn't exist.""" >> >> try: >> with self.engine.db_binder.get_manager(self.output_binding) >> as dbm: >> # Check if table exists >> if self.table_name not in dbm.connection.tables(): >> loginf(f"Creating table {self.table_name}") >> >> # Create the table >> dbm.connection.execute( >> f"CREATE TABLE {self.table_name} (" >> f"dateTime INTEGER NOT NULL PRIMARY KEY, " >> f"usUnits INTEGER NOT NULL, " >> f"`interval` INTEGER NOT NULL, " >> f"min_temp DOUBLE, " >> f"min_temp_time INTEGER, " >> f"max_temp DOUBLE, " >> f"max_temp_time INTEGER)" >> ) >> except Exception as e: >> logerr(f"Error initializing table: {e}") >> >> def new_archive_record(self, event): >> """Called when a new archive record is available. >> >> Check if it's just after 9am and if so, record the min/max data >> for the 6pm-9am period. >> """ >> >> timestamp = event.record['dateTime'] >> dt = datetime.datetime.fromtimestamp(timestamp) >> >> # Only process records at or just after 9am >> if dt.hour == BOM_MORNING_HOUR and dt.minute < 10: >> self.process_bom_minmax(timestamp) >> >> def process_bom_minmax(self, current_ts): >> """Process and record BoM min/max temperatures. >> >> Args: >> current_ts: Current timestamp (around 9am) >> """ >> >> # Convert timestamp to datetime >> current_dt = datetime.datetime.fromtimestamp(current_ts) >> >> # Calculate the timestamp for 6pm yesterday >> yesterday = current_dt - datetime.timedelta(days=1) >> yesterday_6pm = datetime.datetime(yesterday.year, yesterday.month, >> >> yesterday.day, BOM_EVENING_HOUR, >> 0, 0) >> start_ts = int(yesterday_6pm.timestamp()) >> >> # Calculate the timestamp for 9am today >> today_9am = datetime.datetime(current_dt.year, current_dt.month, >> current_dt.day, BOM_MORNING_HOUR, 0, >> 0) >> end_ts = int(today_9am.timestamp()) >> >> loginf(f"Processing BoM min/max data for {yesterday_6pm.strftime( >> '%Y-%m-%d %H:%M')} to {today_9am.strftime('%Y-%m-%d %H:%M')}") >> >> try: >> # Get the temperature data from the archive >> with self.engine.db_binder.get_manager(self.archive_binding) >> as dbm_archive: >> # Get min temperature >> min_temp_data = dbm_archive.getSql( >> f"SELECT MIN({self.temp_field}), dateTime, usUnits >> FROM archive " >> f"WHERE dateTime >= {start_ts} AND dateTime <= { >> end_ts} " >> f"AND {self.temp_field} IS NOT NULL") >> >> # Get max temperature >> max_temp_data = dbm_archive.getSql( >> f"SELECT MAX({self.temp_field}), dateTime, usUnits >> FROM archive " >> f"WHERE dateTime >= {start_ts} AND dateTime <= { >> end_ts} " >> f"AND {self.temp_field} IS NOT NULL") >> >> # Skip if no data available >> if not min_temp_data or not max_temp_data: >> loginf("Insufficient temperature data for period, >> skipping") >> return >> >> # Create the record >> record = { >> 'dateTime': end_ts, >> 'usUnits': min_temp_data[2], # Use the same unit >> system from archive >> 'interval': 1440, # 24 hours in minutes >> 'min_temp': min_temp_data[0], >> 'min_temp_time': min_temp_data[1], >> 'max_temp': max_temp_data[0], >> 'max_temp_time': max_temp_data[1] >> } >> >> # Store in the output database >> with self.engine.db_binder.get_manager(self. >> output_binding) as dbm_output: >> dbm_output.addRecord(record) >> >> # Log the min/max data >> min_temp_time = datetime.datetime.fromtimestamp( >> min_temp_data[1]) >> max_temp_time = datetime.datetime.fromtimestamp( >> max_temp_data[1]) >> >> loginf(f"Recorded BoM min/max: Min {min_temp_data[0]:.1f}°C >> at {min_temp_time.strftime('%H:%M')}, " >> f"Max {max_temp_data[0]:.1f}°C at {max_temp_time. >> strftime('%H:%M')}") >> >> except Exception as e: >> logerr(f"Error processing BoM min/max: {e}") >> >> # To use this service, add to weewx.conf: >> # >> # [BomMinMax] >> # # Database binding to read temperature data from >> # archive_binding = wx_binding >> # # Database binding to store BoM min/max data (can be same as >> archive_binding) >> # output_binding = wx_binding >> # # Table name for BoM min/max data >> # table_name = archive_bom_minmax >> # # Temperature field to monitor (default: outTemp) >> # temp_field = outTemp >> # >> # [Engine] >> # [[Services]] >> # data_services = ..., user.bom_minmax.BomMinMaxService, ... >> >> >> That should work, I disable the table checking as that caused me to >> error. >> I also installed weewx as a package not via pip. >> >> Guess we know tomorrow here in AU if it works :-). >> >> Let me know how you go. >> H. >> (https://dayboro.au) >> >> On Mon, 24 Mar 2025 at 13:38, Dr Henk Harms <drhen...@gmail.com> wrote: >> >>> I ran that query or similar on my mariadb... took forever. >>> Would it not be simpler to have an table called archive_day_bom_minmax >>> and have a weewx service write to that table at 9am each day? >>> >>> >>> On Thu, 20 Mar 2025 at 18:31, Mike B. <ozcz...@gmail.com> wrote: >>> >>>> Hi All, >>>> >>>> I am trying to capture a new observation: "Highest Nighttime Min >>>> Temperature". I am using this logic "The running min, a value the Bureau Of >>>> Meteorology uses to highlight the lowest temperature between 6pm and 9am" >>>> >>>> I have a query against archive table (MariaDb) >>>> >>>> SELECT (x.night + INTERVAL 1 DAY) AS night, >>>> UNIX_TIMESTAMP(x.night), >>>> x.lowestNightTemp >>>> FROM ( >>>> SELECT CAST(FROM_UNIXTIME(dateTime) AS DATE) - >>>> INTERVAL 9 HOUR AS night, >>>> MAX((a.outTemp-32)*(5/9)) AS highestNightTemp, >>>> MIN((a.outTemp-32)*(5/9)) AS lowestNightTemp, >>>> DATE_ADD(DATE_SUB(CAST(FROM_UNIXTIME(dateTime) >>>> AS DATE), INTERVAL 1 DAY), INTERVAL 18 HOUR) AS DayBefore, >>>> DATE_ADD(CAST(FROM_UNIXTIME(dateTime) AS DATE), >>>> INTERVAL 9 HOUR) AS Day >>>> FROM archive AS a >>>> WHERE a.dateTime BETWEEN >>>> UNIX_TIMESTAMP(DATE_ADD(DATE_SUB(CAST >>>> (FROM_UNIXTIME(dateTime) AS DATE), INTERVAL 1 DAY), INTERVAL 18 HOUR)) >>>> >>>> AND >>>> UNIX_TIMESTAMP(DATE_ADD(CAST(FROM_UNIXTIME( >>>> dateTime) AS DATE), INTERVAL 9 HOUR)) >>>> GROUP BY night >>>> ) AS x >>>> ORDER BY x.lowestNightTemp DESC LIMIT 1 >>>> >>>> The above query seems to work, as it returns the Highest lowest >>>> Temperature between 6pm and 9am. >>>> >>>> I am trying to work out how to integrate this into the weewx process. I >>>> want to: >>>> * Run a service or something once a day (say midnight) and then for >>>> each "day" (defined as 6pm to 9am) store the summary >>>> * If I run rebuild daily summaries (weectl database) ideally this >>>> process should also run >>>> * Add result to records to have something like: >>>> "Highest Minimum overnight Temperature 29.111 C 23 Mar >>>> 2025" >>>> >>>> I created a service "class NighttimeTempTracker(StdService)" and added >>>> it to "data_services"...but it runs for each ARCHIVE PERIOD >>>> (weewx.NEW_ARCHIVE_RECORD) >>>> and cannot span multiple days. >>>> >>>> I am out of ideas in which ways I can achieve the above via weewx >>>> process. Any help, pointers, sample code or projects would be highly >>>> appreciated. >>>> >>>> Thanks >>>> >>>> Mike >>>> >>>> >>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "weewx-user" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to weewx-user+...@googlegroups.com. >>>> To view this discussion visit >>>> https://groups.google.com/d/msgid/weewx-user/31513f26-63d1-4e47-a903-9c584ba64a7cn%40googlegroups.com >>>> <https://groups.google.com/d/msgid/weewx-user/31513f26-63d1-4e47-a903-9c584ba64a7cn%40googlegroups.com?utm_medium=email&utm_source=footer> >>>> . >>>> >>> -- > You received this message because you are subscribed to the Google Groups > "weewx-user" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to weewx-user+unsubscr...@googlegroups.com. > To view this discussion visit > https://groups.google.com/d/msgid/weewx-user/6508b98a-abff-425d-8c84-c417cafb13ddn%40googlegroups.com > <https://groups.google.com/d/msgid/weewx-user/6508b98a-abff-425d-8c84-c417cafb13ddn%40googlegroups.com?utm_medium=email&utm_source=footer> > . > -- You received this message because you are subscribed to the Google Groups "weewx-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to weewx-user+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/weewx-user/CANcmcPVsQan8nDxxvWViSZUTYEBUOfMoJbdkjd1aiWDAZHQPeA%40mail.gmail.com.