diff --git a/.gitignore b/.gitignore index 68bc17f..e05e2e7 100644 --- a/.gitignore +++ b/.gitignore @@ -158,3 +158,4 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +.DS_Store diff --git a/async_test.py b/async_test.py index 242d093..9618c62 100644 --- a/async_test.py +++ b/async_test.py @@ -28,20 +28,40 @@ async def main() -> None: _database = os.getenv("DATABASE") _id = os.getenv("ID") - weather = MeteobridgeSQL(_host, _user, _password, _database) - await weather.async_init() - - result = await weather.async_get_realtime_data(_id) - print("") - print("========================================================") - print("ID: ", result.ID) - print("FEELS LIKE: ", result.feels_like_temperature) - print("TEMPERATURE: ", result.temperature) - print("RAIN TODAY: ", result.raintoday) - print("WIND BEARING: ", result.windbearing) - print("WIND DIRECTION: ", result.wind_direction) - print("WIND GUST: ", result.windgust) - print("") + try: + weather = MeteobridgeSQL(_host, _user, _password, _database) + await weather.async_init() + + result = await weather.async_get_realtime_data(_id) + print("") + print("========================================================") + print("ID: ", result.ID) + print("FEELS LIKE: ", result.feels_like_temperature) + print("TEMPERATURE: ", result.temperature) + print("RAIN TODAY: ", result.raintoday) + print("WIND BEARING: ", result.windbearing) + print("WIND DIRECTION: ", result.wind_direction) + print("WIND GUST: ", result.windgust) + print("") + + except Exception as err: + print(err) + + try: + result = await weather.async_get_station_data(_id) + print("") + print("========================================================") + print("ID: ", result.ID) + print("IP: ", result.mb_ip) + print("SW Version: ", result.mb_swversion) + print("BUILD NUM: ", result.mb_buildnum) + print("PLATFORM: ", result.mb_platform) + print("STATION: ", result.mb_station) + print("STATION NAME: ", result.mb_stationname) + print("") + + except Exception as err: + print(err) end = time.time() diff --git a/pymeteobridgesql/__init__.py b/pymeteobridgesql/__init__.py index e413248..c8360a1 100644 --- a/pymeteobridgesql/__init__.py +++ b/pymeteobridgesql/__init__.py @@ -3,8 +3,8 @@ from __future__ import annotations -from .api import MeteobridgeSQL -from .data import RealtimeData +from .api import MeteobridgeSQL, MeteobridgeSQLDatabaseConnectionError, MeteobridgeSQLDataError +from .data import RealtimeData, StationData __title__ = "pymeteobridgesql" __version__ = "1.0.0" diff --git a/pymeteobridgesql/api.py b/pymeteobridgesql/api.py index d4955fb..065e001 100644 --- a/pymeteobridgesql/api.py +++ b/pymeteobridgesql/api.py @@ -4,10 +4,17 @@ import logging import mysql.connector -from .data import RealtimeData +from .data import RealtimeData, StationData _LOGGER = logging.getLogger(__name__) +class MeteobridgeSQLDatabaseConnectionError(Exception): + """Cannot connect to database.""" + + +class MeteobridgeSQLDataError(Exception): + """Cannot lookup data in the database.""" + class MeteobridgeSQL: """Class that interfaces with a MySQL database, with weather data supplied by Meteobridge.""" @@ -32,22 +39,43 @@ def __init__( async def async_init(self) -> None: """Initialize the connection.""" - self._weatherdb = mysql.connector.connect( - host=self._host, - user=self._user, - password=self._password, - database=self._database, - port=self._port, - ) + try: + self._weatherdb = mysql.connector.connect( + host=self._host, + user=self._user, + password=self._password, + database=self._database, + port=self._port, + ) + except mysql.connector.Error as err: + raise MeteobridgeSQLDatabaseConnectionError(f"Failed to connect to the database: {err.msg}") self._weather_cursor = self._weatherdb.cursor() async def async_get_realtime_data(self, id: str) -> RealtimeData: """Get the latest data from the database.""" - self._weather_cursor.execute( - f"SELECT * FROM realtime_data WHERE ID = '{id}'" - ) - result = self._weather_cursor.fetchone() + + try: + self._weather_cursor.execute( + f"SELECT * FROM realtime_data WHERE ID = '{id}'" + ) + result = self._weather_cursor.fetchone() + except mysql.connector.Error as err: + raise MeteobridgeSQLDataError(f"Failed to lookup data in the database: {err.msg}") return RealtimeData(*result) + async def async_get_station_data(self, id: str) -> RealtimeData: + """Get station data from the database.""" + + try: + self._weather_cursor.execute( + f"SELECT ID, mb_ip, mb_swversion, mb_buildnum, mb_platform, mb_station, mb_stationname FROM realtime_data WHERE ID = '{id}'" + ) + result = self._weather_cursor.fetchone() + except mysql.connector.Error as err: + raise MeteobridgeSQLDataError(f"Failed to lookup data in the database: {err.msg}") + + return StationData(*result) + + diff --git a/pymeteobridgesql/data.py b/pymeteobridgesql/data.py index e8e0ae2..34e6300 100644 --- a/pymeteobridgesql/data.py +++ b/pymeteobridgesql/data.py @@ -31,6 +31,12 @@ class RealtimeData: solarrad: float solarraddaymax: float pressuretrend: float + mb_ip: str + mb_swversion: str + mb_buildnum: str + mb_platform: str + mb_station: str + mb_stationname: str @property def wind_direction(self) -> str: @@ -63,4 +69,14 @@ def pressuretrend_text(self) -> str: return "rising" if self.pressuretrend < 0: return "falling" - return "steady" \ No newline at end of file + return "steady" + +@dataclasses.dataclass +class StationData: + ID: str + mb_ip: str + mb_swversion: str + mb_buildnum: str + mb_platform: str + mb_station: str + mb_stationname: str diff --git a/sql/create_database.sql b/sql/create_database.sql index 3bdf97c..9c914f0 100644 --- a/sql/create_database.sql +++ b/sql/create_database.sql @@ -7,7 +7,6 @@ CREATE TABLE `realtime_data` ( `pm1` FLOAT NULL DEFAULT 'NULL' , `pm25` FLOAT NULL DEFAULT 'NULL' , `pm10` FLOAT NULL DEFAULT 'NULL' , --- `aqi` INT NULL DEFAULT 'NULL' , `heatindex` FLOAT NULL DEFAULT 'NULL' , `temp15min` FLOAT NULL DEFAULT 'NULL' , `humidity` INT NULL DEFAULT 'NULL' , @@ -17,27 +16,28 @@ CREATE TABLE `realtime_data` ( `rainrate` FLOAT NULL DEFAULT 'NULL' , `raintoday` FLOAT NULL DEFAULT 'NULL' , `rainyesterday` FLOAT NULL DEFAULT 'NULL' , --- `precipprob` INT NULL DEFAULT 'NULL' , `windbearing` INT NULL DEFAULT 'NULL' , `beaufort` INT NULL DEFAULT 'NULL' , --- `windcardinal` VARCHAR(3) NULL DEFAULT 'NULL' , `sealevelpressure` FLOAT NULL DEFAULT 'NULL' , `uv` FLOAT NULL DEFAULT 'NULL' , `uvdaymax` FLOAT NULL DEFAULT 'NULL' , `solarrad` FLOAT NULL DEFAULT 'NULL' , `solarraddaymax` FLOAT NULL DEFAULT 'NULL' , --- `feelslike` FLOAT NULL DEFAULT 'NULL' , --- `visibility` INT NULL DEFAULT 'NULL' , --- `condition` VARCHAR(50) NULL DEFAULT 'NULL' , --- `conditiontext` VARCHAR(250) NULL DEFAULT 'NULL' , `pressuretrend` FLOAT NULL DEFAULT 'NULL' , --- `pressuretrendtext` VARCHAR(10) NULL DEFAULT 'NULL' , + `mb_ip` VARCHAR(20) NULL DEFAULT 'NULL' , + `mb_swversion` VARCHAR(20) NULL DEFAULT 'NULL' , + `mb_buildnum` VARCHAR(10) NULL DEFAULT 'NULL' , + `mb_platform` VARCHAR(20) NULL DEFAULT 'NULL' , + `mb_station` VARCHAR(20) NULL DEFAULT 'NULL' , + `mb_stationname` VARCHAR(50) NULL DEFAULT 'NULL' , CONSTRAINT `PRIMARY` PRIMARY KEY (`ID`), CONSTRAINT `primary_index` UNIQUE (`ID`) ); + -- This is the string used on the Meteobridge Service settings page to update the values. You must create a row with the [mbsystem-mac:0] as ID before starting -UPDATE `realtime_data` SET `temperature` = '[th0temp-act:0]',`tempmax` = '[th0temp-dmax:0]', `tempmin` = '[th0temp-dmin:0]', `windchill` = '[wind0chill-act:0]', `pm1` = '[air0pm-act:0]', `pm25` = '[air1pm-act:0]', `pm10` = '[air2pm-act:0]', `heatindex` = '[th0heatindex-act:0]', `temp15min` = '[th0temp-val15:0]', `humidity` = '[th0hum-act:0]', `windspeedavg` = '[wind0avgwind-act:0]', `windgust` = '[wind0wind-max10:0]', `dewpoint` = '[th0dew-act:0]', `rainrate` = '[rain0rate-act:0]', `raintoday` = '[rain0total-daysum:0]', `rainyesterday` = '[rain0total-ydaysum:0]', `windbearing` = '[wind0dir-act:0]', `beaufort` = '[wind0wind-act=bft.0:0]', `sealevelpressure` = '[thb0seapress-act:0]', `uv` = '[uv0index-act:0]', `uvdaymax` = '[uv0index-dmax:0]', `solarrad` = '[sol0rad-act:0]', `solarraddaymax` = '[sol0rad-dmax:0]', `pressuretrend` = '[thb0seapress-delta3h:0]' WHERE `ID` = '[mbsystem-mac:0]' +UPDATE `realtime_data` SET `temperature` = '[th0temp-act:0]',`tempmax` = '[th0temp-dmax:0]', `tempmin` = '[th0temp-dmin:0]', `windchill` = '[wind0chill-act:0]', `pm1` = '[air0pm-act:0]', `pm25` = '[air1pm-act:0]', `pm10` = '[air2pm-act:0]', `heatindex` = '[th0heatindex-act:0]', `temp15min` = '[th0temp-val15:0]', `humidity` = '[th0hum-act:0]', `windspeedavg` = '[wind0avgwind-act:0]', `windgust` = '[wind0wind-max10:0]', `dewpoint` = '[th0dew-act:0]', `rainrate` = '[rain0rate-act:0]', `raintoday` = '[rain0total-daysum:0]', `rainyesterday` = '[rain0total-ydaysum:0]', `windbearing` = '[wind0dir-act:0]', `beaufort` = '[wind0wind-act=bft.0:0]', `sealevelpressure` = '[thb0seapress-act:0]', `uv` = '[uv0index-act:0]', `uvdaymax` = '[uv0index-dmax:0]', `solarrad` = '[sol0rad-act:0]', `solarraddaymax` = '[sol0rad-dmax:0]', `pressuretrend` = '[thb0seapress-delta3h:0]', `mb_ip` = '[mbsystem-ip:-]', `mb_swversion` = '[mbsystem-swversion:-]', `mb_buildnum` = '[mbsystem-buildnum:-]', `mb_platform` = '[mbsystem-platform:-]', `mb_station` = '[mbsystem-station:-]' WHERE `ID` = '[mbsystem-mac:0]' + SELECT JSON_OBJECT( 'ID', ID,