juham-visualcrossing 0.0.1__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ include docs/source/README.rst
2
+ include docs/source/CHANGELOG.rst
3
+ include docs/source/LICENSE.rst
4
+ include docs/source/CONTRIBUTING.rst
5
+
6
+ recursive-include tests *
7
+ recursive-include docs/build/html *
8
+
9
+ # files to be excluded
10
+ global-exclude *~ \#*
11
+
@@ -0,0 +1,88 @@
1
+ Metadata-Version: 2.1
2
+ Name: juham_visualcrossing
3
+ Version: 0.0.1
4
+ Summary: A Weather forecast plugin extending `juham` applications
5
+ Author-email: J Meskanen <juham.api@gmail.com>
6
+ Maintainer-email: "J. Meskanen" <juham.api@gmail.com>
7
+ License: MIT License
8
+ ===========
9
+
10
+ Copyright (c) 2024, Juha Meskanen
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+
29
+
30
+ Project-URL: Homepage, https://meskanen.com
31
+ Project-URL: Bug Reports, https://meskanen.com
32
+ Project-URL: Funding, https://meskanen.com
33
+ Project-URL: Say Thanks!, http://meskanen.com
34
+ Project-URL: Source, https://meskanen.com
35
+ Keywords: object-oriented,plugin,framework
36
+ Classifier: Development Status :: 1 - Planning
37
+ Classifier: Intended Audience :: Developers
38
+ Classifier: Topic :: Software Development
39
+ Classifier: License :: OSI Approved :: MIT License
40
+ Classifier: Programming Language :: Python :: 3.8
41
+ Requires-Python: >=3.8
42
+ Description-Content-Type: text/markdown
43
+ Requires-Dist: juham>=0.0.7
44
+ Requires-Dist: pytz>=2024.1
45
+ Requires-Dist: importlib-metadata
46
+ Provides-Extra: dev
47
+ Requires-Dist: check-manifest; extra == "dev"
48
+
49
+ juham_visualcrossing
50
+ ====================
51
+
52
+ `juham_visualcrossing` plugs VisualCrossing weather forecast service to Juham - Juha's Ultimate
53
+ Home Automation Masterpiece application.
54
+
55
+
56
+
57
+ Features
58
+ --------
59
+
60
+ The main purpose is to acquire solar energy forecast, for optimizing energy management in
61
+ homes with solar panels.
62
+
63
+
64
+ Installation
65
+ ------------
66
+
67
+ The installation is two stage process
68
+
69
+ 1. To install:
70
+
71
+ .. code-block:: python
72
+
73
+ pip install juham_visualcrossing
74
+
75
+
76
+ 2. Configure
77
+
78
+ VisualCrossing requires you to register and obtain web key, through which you can
79
+ access their forecast services. So sign in to visualcrossing.com to obtain the key,
80
+ and then add the web key to the '~/.[app]/config/VisualCrossing.json' configuration
81
+ file.
82
+
83
+
84
+
85
+ License
86
+ -------
87
+
88
+ This project is licensed under the MIT License - see the `LICENSE` file for details.
@@ -0,0 +1,8 @@
1
+ Changelog
2
+ =========
3
+
4
+ [0.0.1] - August 4, 2024
5
+ ------------------------
6
+
7
+ ### Initial release
8
+
@@ -0,0 +1,56 @@
1
+ Contributing
2
+ ============
3
+
4
+
5
+ Thank You!
6
+ ----------
7
+
8
+ Thank you in advance for your forthcoming contributions, whether they are bug fixes,
9
+ documentation improvements, entirely new features, or simply feedback. Your efforts
10
+ will be highly appreciated and will help turn this project from its current mission
11
+ state into an actual masterpiece.
12
+
13
+
14
+ Design Patterns
15
+ ---------------
16
+
17
+ Please read the developer documentation and understand the few design patterns before contributing.
18
+ This will help ensure that your contributions align with the project's design and goals.
19
+ .. todo:: (okay, the documentation is currently lacking many essential chapters, add.)
20
+
21
+
22
+ Code Formatting
23
+ ---------------
24
+
25
+ To help maintain consistent code formatting across different developers, we use 'black' python formatter, by Microsoft.
26
+
27
+ Strange, the formatter doesn't seem to format that much, it doesn't organize imports,
28
+ doesn't adjust docstring lenghts
29
+ .. todo:: most likely I don't know how to use it properly, read the docs.
30
+
31
+
32
+ Building and Packaging
33
+ ----------------------
34
+
35
+ Despite my attempts to fall in love with Eclipse, VSCode and other IDEs, I still find Makefile and Emacs the best
36
+ tools for many of my workflows.
37
+ So there is a Makefile in the root folder. For those old dogs who are like me
38
+ ::
39
+
40
+ make help
41
+
42
+ To create python package out of the 'pyproj.toml':
43
+ ::
44
+
45
+ make build
46
+
47
+ To install using 'venv':
48
+ ::
49
+
50
+ make install
51
+
52
+
53
+ More Stuff
54
+ ----------
55
+ .. todo:: add more stuff, later.
56
+
@@ -0,0 +1,22 @@
1
+ MIT License
2
+ ===========
3
+
4
+ Copyright (c) 2024, Juha Meskanen
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+
@@ -0,0 +1,40 @@
1
+ juham_visualcrossing
2
+ ====================
3
+
4
+ `juham_visualcrossing` plugs VisualCrossing weather forecast service to Juham - Juha's Ultimate
5
+ Home Automation Masterpiece application.
6
+
7
+
8
+
9
+ Features
10
+ --------
11
+
12
+ The main purpose is to acquire solar energy forecast, for optimizing energy management in
13
+ homes with solar panels.
14
+
15
+
16
+ Installation
17
+ ------------
18
+
19
+ The installation is two stage process
20
+
21
+ 1. To install:
22
+
23
+ .. code-block:: python
24
+
25
+ pip install juham_visualcrossing
26
+
27
+
28
+ 2. Configure
29
+
30
+ VisualCrossing requires you to register and obtain web key, through which you can
31
+ access their forecast services. So sign in to visualcrossing.com to obtain the key,
32
+ and then add the web key to the '~/.[app]/config/VisualCrossing.json' configuration
33
+ file.
34
+
35
+
36
+
37
+ License
38
+ -------
39
+
40
+ This project is licensed under the MIT License - see the `LICENSE` file for details.
@@ -0,0 +1,13 @@
1
+ """
2
+ Description
3
+ ===========
4
+
5
+ VisualCrossing weather forecast.
6
+
7
+ """
8
+
9
+ from .visualcrossing import VisualCrossing
10
+
11
+ __all__ = [
12
+ "VisualCrossing",
13
+ ]
@@ -0,0 +1,180 @@
1
+ from datetime import datetime, timedelta, timezone
2
+ import json
3
+
4
+ from typing import Any
5
+ from juham.base import Base
6
+ from juham.web import RCloud, RCloudThread
7
+
8
+
9
+ class VisualCrossingThread(RCloudThread):
10
+ """Asynchronous thread for acquiring forecast from the VisualCrossing
11
+ site."""
12
+
13
+ # class attributes
14
+ _forecast_topic = ""
15
+ _base_url = ""
16
+ _api_key = ""
17
+ _location = ""
18
+ _interval: float = 12 * 3600
19
+
20
+ def __init__(self, client=None):
21
+ """Construct with the given mqtt client. Acquires data from the visual
22
+ crossing web service and publishes the forecast data to
23
+ forecast_topic.
24
+
25
+ Args:
26
+ client (object, optional): MQTT client. Defaults to None.
27
+ """
28
+ super().__init__(client)
29
+ self.mqtt_client = client
30
+
31
+ def update_interval(self) -> float:
32
+ return self._interval
33
+
34
+ # @override
35
+ def make_url(self) -> str:
36
+ if not self._api_key:
37
+ self.error("Uninitialized api_key {self.get_class_id()}: {self._api_key}")
38
+ return ""
39
+ else:
40
+ now = datetime.now()
41
+ end = now + timedelta(days=1)
42
+ start = now.strftime("%Y-%m-%d")
43
+ stop = end.strftime("%Y-%m-%d")
44
+ url = f"{self._base_url}{self._location}/{start}/{stop}?unitGroup=metric&contentType=json&include=hours&key={self._api_key}"
45
+ self.debug(url)
46
+ return url
47
+
48
+ def init(
49
+ self, topic: str, base_url: str, interval: float, api_key: str, location: str
50
+ ) -> None:
51
+ """Initialize the data acquisition thread
52
+
53
+ Args:
54
+ topic (str): mqtt topic to publish the acquired data
55
+ base_url (str): url of the web service
56
+ interval (float): update interval in seconds
57
+ api_key (str): api_key, as required by the web service
58
+ location (str): geographic location
59
+ """
60
+ self._forecast_topic = topic
61
+ self._base_url = base_url
62
+ self._interval = interval
63
+ self._api_key = api_key
64
+ self._location = location
65
+
66
+ # @override
67
+ def process_data(self, data: Any):
68
+ self.info("VisualCrossing process_data()")
69
+ data = data.json()
70
+ forecast = []
71
+ self.info(f"VisualCrossing {data}")
72
+ for day in data["days"]:
73
+ for hour in day["hours"]:
74
+ ts = int(hour["datetimeEpoch"])
75
+ forecast.append(
76
+ {
77
+ "id": "visualcrossing",
78
+ "ts": ts,
79
+ "hour": datetime.fromtimestamp(ts, tz=timezone.utc).strftime(
80
+ "%H"
81
+ ),
82
+ "day": datetime.fromtimestamp(ts, tz=timezone.utc).strftime(
83
+ "%Y%m%d%H"
84
+ ),
85
+ "uvindex": hour["uvindex"],
86
+ "solarradiation": hour["solarradiation"],
87
+ "solarenergy": hour["solarenergy"],
88
+ "cloudcover": hour["cloudcover"],
89
+ "snow": hour["snow"],
90
+ "snowdepth": hour["snowdepth"],
91
+ "pressure": hour["pressure"],
92
+ "temp": hour["temp"],
93
+ "humidity": hour["humidity"],
94
+ "windspeed": hour["windspeed"],
95
+ "winddir": hour["winddir"],
96
+ "dew": hour["dew"],
97
+ }
98
+ )
99
+ msg = json.dumps(forecast)
100
+ self.publish(self._forecast_topic, msg, qos=1, retain=False)
101
+ self.info(f"VisualCrossing forecast published to {self._forecast_topic}")
102
+
103
+
104
+ class VisualCrossing(RCloud):
105
+ """Constructs a data acquisition object for reading weather
106
+ forecasts from the VisualCrossing web service. Subscribes to the
107
+ forecast topic and writes hourly data such as solar energy, temperature,
108
+ and other attributes relevant to home automation into a time series
109
+ database.
110
+
111
+ Spawns an asynchronous thread to run queries at the specified
112
+ update_interval.
113
+ """
114
+
115
+ workerThreadId = VisualCrossingThread.get_class_id()
116
+ forecast_topic = Base.mqtt_root_topic + "/forecast"
117
+ base_url = "https://weather.visualcrossing.com/VisualCrossingWebServices/rest/services/timeline/"
118
+ update_interval = 12 * 3600
119
+ api_key = "SE9W7EHP775N7NDNW8ANM2MZN"
120
+ location = "lahti,finland"
121
+
122
+ def __init__(self, name="visualcrossing"):
123
+ super().__init__(name)
124
+ self.debug(f"VisualCrossing created")
125
+
126
+ def on_connect(self, client, userdata, flags, rc):
127
+ super().on_connect(client, userdata, flags, rc)
128
+ if rc == 0:
129
+ self.subscribe(self.forecast_topic)
130
+ self.debug(f"VisualCrossing subscribed to topic {self.forecast_topic}")
131
+
132
+ def on_message(self, client, userdata, msg):
133
+ if msg.topic == self.forecast_topic:
134
+ em = json.loads(msg.payload.decode())
135
+ self.on_forecast(em)
136
+ else:
137
+ super().on_message(client, userdata, msg)
138
+
139
+ def on_forecast(self, em: dict) -> None:
140
+ """Handle weather forecast data.
141
+
142
+ Args:
143
+ em (dict): forecast
144
+ """
145
+ self.debug(f"VisualCrossing: got mqtt message {em}")
146
+
147
+ # @override
148
+ def run(self):
149
+ # create, initialize and start the asynchronous thread for acquiring forecast
150
+ self.worker = Base.instantiate(VisualCrossing.workerThreadId)
151
+ self.worker.init(
152
+ self.forecast_topic,
153
+ self.base_url,
154
+ self.update_interval,
155
+ self.api_key,
156
+ self.location,
157
+ )
158
+ self.debug(f"VisualCrossing.run(): base_url is {self.base_url}")
159
+ self.debug(f"VisualCrossing.run(): interval is {self.update_interval}")
160
+ self.debug(f"VisualCrossing.run(): api_key is {self.api_key}")
161
+ self.debug(f"VisualCrossing.run(): location is {self.location}")
162
+ super().run()
163
+
164
+ # @override
165
+ def to_dict(self):
166
+ data = super().to_dict()
167
+ data["_visualcrossing"] = {
168
+ "topic": self.forecast_topic,
169
+ "url": self.base_url,
170
+ "api_key": self.api_key,
171
+ "interval": self.update_interval,
172
+ }
173
+ return data
174
+
175
+ # @override
176
+ def from_dict(self, data):
177
+ super().from_dict(data)
178
+ if "_visualcrossing" in data:
179
+ for key, value in data["_visualcrossing"].items():
180
+ setattr(self, key, value)
@@ -0,0 +1,88 @@
1
+ Metadata-Version: 2.1
2
+ Name: juham_visualcrossing
3
+ Version: 0.0.1
4
+ Summary: A Weather forecast plugin extending `juham` applications
5
+ Author-email: J Meskanen <juham.api@gmail.com>
6
+ Maintainer-email: "J. Meskanen" <juham.api@gmail.com>
7
+ License: MIT License
8
+ ===========
9
+
10
+ Copyright (c) 2024, Juha Meskanen
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+
29
+
30
+ Project-URL: Homepage, https://meskanen.com
31
+ Project-URL: Bug Reports, https://meskanen.com
32
+ Project-URL: Funding, https://meskanen.com
33
+ Project-URL: Say Thanks!, http://meskanen.com
34
+ Project-URL: Source, https://meskanen.com
35
+ Keywords: object-oriented,plugin,framework
36
+ Classifier: Development Status :: 1 - Planning
37
+ Classifier: Intended Audience :: Developers
38
+ Classifier: Topic :: Software Development
39
+ Classifier: License :: OSI Approved :: MIT License
40
+ Classifier: Programming Language :: Python :: 3.8
41
+ Requires-Python: >=3.8
42
+ Description-Content-Type: text/markdown
43
+ Requires-Dist: juham>=0.0.7
44
+ Requires-Dist: pytz>=2024.1
45
+ Requires-Dist: importlib-metadata
46
+ Provides-Extra: dev
47
+ Requires-Dist: check-manifest; extra == "dev"
48
+
49
+ juham_visualcrossing
50
+ ====================
51
+
52
+ `juham_visualcrossing` plugs VisualCrossing weather forecast service to Juham - Juha's Ultimate
53
+ Home Automation Masterpiece application.
54
+
55
+
56
+
57
+ Features
58
+ --------
59
+
60
+ The main purpose is to acquire solar energy forecast, for optimizing energy management in
61
+ homes with solar panels.
62
+
63
+
64
+ Installation
65
+ ------------
66
+
67
+ The installation is two stage process
68
+
69
+ 1. To install:
70
+
71
+ .. code-block:: python
72
+
73
+ pip install juham_visualcrossing
74
+
75
+
76
+ 2. Configure
77
+
78
+ VisualCrossing requires you to register and obtain web key, through which you can
79
+ access their forecast services. So sign in to visualcrossing.com to obtain the key,
80
+ and then add the web key to the '~/.[app]/config/VisualCrossing.json' configuration
81
+ file.
82
+
83
+
84
+
85
+ License
86
+ -------
87
+
88
+ This project is licensed under the MIT License - see the `LICENSE` file for details.
@@ -0,0 +1,20 @@
1
+ MANIFEST.in
2
+ pyproject.toml
3
+ docs/source/LICENSE.rst
4
+ docs/source/README.rst
5
+ docs/source/CHANGELOG.rst
6
+ docs/source/CONTRIBUTING.rst
7
+ docs/source/LICENSE.rst
8
+ docs/source/README.rst
9
+ juham_visualcrossing/__init__.py
10
+ juham_visualcrossing/visualcrossing.py
11
+ juham_visualcrossing.egg-info/PKG-INFO
12
+ juham_visualcrossing.egg-info/SOURCES.txt
13
+ juham_visualcrossing.egg-info/dependency_links.txt
14
+ juham_visualcrossing.egg-info/entry_points.txt
15
+ juham_visualcrossing.egg-info/requires.txt
16
+ juham_visualcrossing.egg-info/top_level.txt
17
+ tests/__init__.py
18
+ tests/test_visualcrossing.py
19
+ tests/__pycache__/__init__.cpython-312.pyc
20
+ tests/__pycache__/test_visualcrossing.cpython-312.pyc
@@ -0,0 +1,2 @@
1
+ [juham.plugins]
2
+ visualcrossing_plugin = juham_visualcrossing:VisualCrossing
@@ -0,0 +1,6 @@
1
+ juham>=0.0.7
2
+ pytz>=2024.1
3
+ importlib-metadata
4
+
5
+ [dev]
6
+ check-manifest
@@ -0,0 +1 @@
1
+ juham_visualcrossing
@@ -0,0 +1,57 @@
1
+
2
+ [build-system]
3
+ requires = ["setuptools"]
4
+ build-backend = "setuptools.build_meta"
5
+
6
+
7
+ [project]
8
+ name = "juham_visualcrossing"
9
+ version = "0.0.1"
10
+ description = "A Weather forecast plugin extending `juham` applications"
11
+ readme = {file = "docs/source/README.rst", content-type = "text/markdown"}
12
+ requires-python = ">=3.8"
13
+ license = {file = "docs/source/LICENSE.rst", content-type = "text/markdown"}
14
+ keywords = ["object-oriented", "plugin", "framework"]
15
+ authors = [
16
+ {name = "J Meskanen", email = "juham.api@gmail.com" }
17
+ ]
18
+ maintainers = [
19
+ {name = "J. Meskanen", email = "juham.api@gmail.com" }
20
+ ]
21
+
22
+ classifiers = [
23
+ "Development Status :: 1 - Planning",
24
+ "Intended Audience :: Developers",
25
+ "Topic :: Software Development",
26
+ "License :: OSI Approved :: MIT License",
27
+ "Programming Language :: Python :: 3.8",
28
+ ]
29
+
30
+ dependencies = [
31
+ "juham >= 0.0.7",
32
+ "pytz >= 2024.1",
33
+ "importlib-metadata"
34
+ ]
35
+
36
+
37
+ [project.optional-dependencies]
38
+ dev = ["check-manifest"]
39
+
40
+
41
+ [project.entry-points."juham.plugins"]
42
+ visualcrossing_plugin = "juham_visualcrossing:VisualCrossing"
43
+
44
+
45
+
46
+ [project.urls]
47
+ "Homepage" = "https://meskanen.com"
48
+ "Bug Reports" = "https://meskanen.com"
49
+ "Funding" = "https://meskanen.com"
50
+ "Say Thanks!" = "http://meskanen.com"
51
+ "Source" = "https://meskanen.com"
52
+
53
+
54
+
55
+ [tool.mypy]
56
+ files = ["juham_visualcrossing/"]
57
+ ignore_missing_imports = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,16 @@
1
+ import unittest
2
+
3
+ from juham_visualcrossing import VisualCrossing
4
+
5
+
6
+ class TestVisualCrossing(unittest.TestCase):
7
+ """Unit tests for `VisualCrossing` weather forecast masterpiece."""
8
+
9
+ def test_get_classid(self):
10
+ """Assert that the meta-class driven class initialization works."""
11
+ classid = VisualCrossing.get_class_id()
12
+ self.assertEqual("VisualCrossing", classid)
13
+
14
+
15
+ if __name__ == "__main__":
16
+ unittest.main()