pymbrewclient 1.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ # “Commons Clause” License Condition v1.0
2
+ #
3
+ # The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition.
4
+ #
5
+ # Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, the right to Sell the Software.
6
+ #
7
+ # For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Clause License Condition notice.
8
+ #
9
+ # Software: pymbrewclient
10
+ # License: MIT License
11
+ # Licensor: Stuart Pearson
12
+ #
13
+ #
14
+ # MIT License
15
+ #
16
+ # Copyright (c) 2024 Stuart Pearson
17
+ #
18
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
19
+ # of this software and associated documentation files (the "Software"), to deal
20
+ # in the Software without restriction, including without limitation the rights
21
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22
+ # copies of the Software, and to permit persons to whom the Software is
23
+ # furnished to do so, subject to the following conditions:
24
+ #
25
+ # The above copyright notice and this permission notice shall be included in all
26
+ # copies or substantial portions of the Software.
27
+ #
28
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34
+ # SOFTWARE.
35
+ #
36
+ # Disclaimer: This software is an independent project and is not affiliated with, endorsed by, or associated with MiniBrew. MiniBrew's trademarks, logos, API, and other intellectual property are owned by MiniBrew and are not included in this software. Users are responsible for complying with MiniBrew's terms of service when using this software.
pymbrewclient/cli.py ADDED
@@ -0,0 +1,274 @@
1
+ # “Commons Clause” License Condition v1.0
2
+ #
3
+ # The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition.
4
+ #
5
+ # Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, the right to Sell the Software.
6
+ #
7
+ # For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Clause License Condition notice.
8
+ #
9
+ # Software: pymbrewclient
10
+ # License: MIT License
11
+ # Licensor: Stuart Pearson
12
+ #
13
+ #
14
+ # MIT License
15
+ #
16
+ # Copyright (c) 2024 Stuart Pearson
17
+ #
18
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
19
+ # of this software and associated documentation files (the "Software"), to deal
20
+ # in the Software without restriction, including without limitation the rights
21
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22
+ # copies of the Software, and to permit persons to whom the Software is
23
+ # furnished to do so, subject to the following conditions:
24
+ #
25
+ # The above copyright notice and this permission notice shall be included in all
26
+ # copies or substantial portions of the Software.
27
+ #
28
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34
+ # SOFTWARE.
35
+ #
36
+ # Disclaimer: This software is an independent project and is not affiliated with, endorsed by, or associated with MiniBrew. MiniBrew's trademarks, logos, API, and other intellectual property are owned by MiniBrew and are not included in this software. Users are responsible for complying with MiniBrew's terms of service when using this software.import typer
37
+ import typer
38
+ from pymbrewclient.rest.client import RestApiClient
39
+ from rich import print as rich_print
40
+ from rich.pretty import Pretty
41
+ from loguru import logger
42
+ import json
43
+ from pydantic import BaseModel
44
+ from typing import Annotated
45
+ import sys
46
+
47
+ app = typer.Typer(help="CLI for reading information from the Minibrew Pro Portal.", no_args_is_help=True)
48
+
49
+ base_url = "https://api.minibrew.io"
50
+
51
+
52
+ def initialize_client(base_url: str, username: str, password: str) -> RestApiClient:
53
+ """
54
+ Initialize the RestApiClient with the provided credentials.
55
+ """
56
+ return RestApiClient(base_url=base_url, username=username, password=password)
57
+
58
+
59
+ def print_output(data: BaseModel | dict | list, format: str) -> None:
60
+ """Print output in the specified format."""
61
+ if isinstance(data, BaseModel):
62
+ data = data.dict()
63
+
64
+ if format == "json":
65
+ typer.echo(json.dumps(data, indent=4))
66
+ else:
67
+ rich_print(Pretty(data))
68
+
69
+
70
+ def setup_logging(level: str) -> None:
71
+ """Configure loguru with the specified log level."""
72
+ logger.remove() # Remove any default handlers
73
+ logger.add(sink=sys.stderr, level=level.upper()) # Add a new handler with the specified level
74
+
75
+
76
+ @app.callback()
77
+ def configure(
78
+ logging_level: Annotated[
79
+ str,
80
+ typer.Option(
81
+ "--logging-level",
82
+ help="Set the logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)",
83
+ case_sensitive=False,
84
+ ),
85
+ ] = "INFO",
86
+ ) -> None:
87
+ """
88
+ CLI for reading information from the MiniBrew Pro Portal.
89
+ """
90
+ setup_logging(logging_level)
91
+
92
+
93
+ @app.command()
94
+ def get_token(
95
+ username: str = typer.Option(..., "--username", help="The username for authentication."),
96
+ password: str = typer.Option(..., "--password", help="The password for authentication."),
97
+ base_url: str = typer.Option(base_url, "--base-url", help="The base URL for the API."),
98
+ ) -> None:
99
+ """
100
+ Fetch and display the token.
101
+ """
102
+ try:
103
+ logger.info("Fetching token...")
104
+ client = initialize_client(base_url, username, password)
105
+ token_response = client._get_token()
106
+ print_output(token_response, "pretty")
107
+ except Exception as e:
108
+ logger.error(f"Error fetching token: {e}")
109
+ typer.echo(f"Error fetching token: {e}")
110
+ raise typer.Exit(code=1)
111
+
112
+
113
+ @app.command()
114
+ def get_brewery_overview(
115
+ username: str = typer.Option(..., "--username", help="The username for authentication."),
116
+ password: str = typer.Option(..., "--password", help="The password for authentication."),
117
+ base_url: str = typer.Option(base_url, "--base-url", help="The base URL for the API."),
118
+ ) -> None:
119
+ """
120
+ Fetch and display the brewery overview.
121
+ """
122
+ try:
123
+ logger.info("Fetching brewery overview...")
124
+ client = initialize_client(base_url, username, password)
125
+ overview = client.get_brewery_overview()
126
+ print_output(overview, "pretty")
127
+ except Exception as e:
128
+ logger.error(f"Error fetching brewery overview: {e}")
129
+ typer.echo(f"Error fetching brewery overview: {e}")
130
+ raise typer.Exit(code=1)
131
+
132
+
133
+ @app.command()
134
+ def get_session_info(
135
+ username: str = typer.Option(..., "--username", help="The username for authentication."),
136
+ password: str = typer.Option(..., "--password", help="The password for authentication."),
137
+ base_url: str = typer.Option(base_url, "--base-url", help="The base URL for the API."),
138
+ sessionid: int = typer.Option(
139
+ ..., "--sessionid", help="The session ID to fetch information for.", flag_value="https://api.minibrew.io"
140
+ ),
141
+ ) -> None:
142
+ """
143
+ Fetch and display session information.
144
+ """
145
+ try:
146
+ logger.info(f"Fetching session info for session ID: {sessionid}...")
147
+ client = initialize_client(base_url, username, password)
148
+ session = client.get_session_info(sessionid)
149
+ print_output(session, "pretty")
150
+ except Exception as e:
151
+ logger.error(f"Error fetching session info: {e}")
152
+ typer.echo(f"Error fetching session info: {e}")
153
+ raise typer.Exit(code=1)
154
+
155
+
156
+ @app.command()
157
+ def get_fermenting(
158
+ username: str = typer.Option(..., "--username", help="The username for authentication."),
159
+ password: str = typer.Option(..., "--password", help="The password for authentication."),
160
+ base_url: str = typer.Option(base_url, "--base-url", help="The base URL for the API."),
161
+ ) -> None:
162
+ """
163
+ Fetch and display fermenting devices.
164
+ """
165
+ try:
166
+ logger.info("Fetching fermenting devices...")
167
+ client = initialize_client(base_url, username, password)
168
+ overview = client.get_brewery_overview()
169
+ print_output(overview.fermenting, "pretty")
170
+ except Exception as e:
171
+ logger.error(f"Error fetching fermenting devices: {e}")
172
+ typer.echo(f"Error fetching fermenting devices: {e}")
173
+ raise typer.Exit(code=1)
174
+
175
+
176
+ @app.command()
177
+ def get_serving(
178
+ username: str = typer.Option(..., "--username", help="The username for authentication."),
179
+ password: str = typer.Option(..., "--password", help="The password for authentication."),
180
+ base_url: str = typer.Option(base_url, "--base-url", help="The base URL for the API."),
181
+ ) -> None:
182
+ """
183
+ Fetch and display serving devices.
184
+ """
185
+ try:
186
+ logger.info("Fetching serving devices...")
187
+ client = initialize_client(base_url, username, password)
188
+ overview = client.get_brewery_overview()
189
+ print_output(overview.serving, "pretty")
190
+ except Exception as e:
191
+ logger.error(f"Error fetching serving devices: {e}")
192
+ typer.echo(f"Error fetching serving devices: {e}")
193
+ raise typer.Exit(code=1)
194
+
195
+
196
+ @app.command()
197
+ def get_brew_clean_idle(
198
+ username: str = typer.Option(..., "--username", help="The username for authentication."),
199
+ password: str = typer.Option(..., "--password", help="The password for authentication."),
200
+ base_url: str = typer.Option(base_url, "--base-url", help="The base URL for the API."),
201
+ ) -> None:
202
+ """
203
+ Fetch and display brew clean idle devices.
204
+ """
205
+ try:
206
+ client = initialize_client(base_url, username, password)
207
+ overview = client.get_brewery_overview()
208
+ print_output(overview.brew_clean_idle, "pretty")
209
+ except Exception as e:
210
+ logger.error(f"Error fetching brew clean idle devices: {e}")
211
+ typer.echo(f"Error fetching brew clean idle devices: {e}")
212
+ raise typer.Exit(code=1)
213
+
214
+
215
+ @app.command()
216
+ def get_brew_acid_clean_idle(
217
+ username: str = typer.Option(..., "--username", help="The username for authentication."),
218
+ password: str = typer.Option(..., "--password", help="The password for authentication."),
219
+ base_url: str = typer.Option(base_url, "--base-url", help="The base URL for the API."),
220
+ ) -> None:
221
+ """
222
+ Fetch and display brew acid clean idle devices.
223
+ """
224
+ try:
225
+ client = initialize_client(base_url, username, password)
226
+ overview = client.get_brewery_overview()
227
+ print_output(overview.brew_acid_clean_idle, "pretty")
228
+ except Exception as e:
229
+ logger.error(f"Error fetching brew acid clean idle devices: {e}")
230
+ typer.echo(f"Error fetching brew acid clean idle devices: {e}")
231
+ raise typer.Exit(code=1)
232
+
233
+
234
+ @app.command()
235
+ def get_minibrew_devices(
236
+ username: str = typer.Option(..., "--username", help="The username for authentication."),
237
+ password: str = typer.Option(..., "--password", help="The password for authentication."),
238
+ base_url: str = typer.Option(base_url, "--base-url", help="The base URL for the API."),
239
+ ) -> None:
240
+ """
241
+ Fetch and display all devices.
242
+ """
243
+ try:
244
+ logger.info("Fetching all devices...")
245
+ client = initialize_client(base_url, username, password)
246
+ overview = client.get_brewery_overview()
247
+ all_devices = overview.brew_clean_idle + overview.fermenting + overview.serving + overview.brew_acid_clean_idle
248
+
249
+ # Only select unique devices and get only uuid, serial_number, title, and software version
250
+ unique_devices = list(
251
+ {
252
+ device["uuid"]: device for device in all_devices if "uuid" in device and device["uuid"] is not None
253
+ }.values()
254
+ )
255
+
256
+ selected_data = [
257
+ {
258
+ "Serial Number": device["serial_number"],
259
+ "Nickname": device["title"],
260
+ "Version": device["software_version"],
261
+ "Is online": device["online"],
262
+ "Stage": device["stage"],
263
+ }
264
+ for device in unique_devices
265
+ ]
266
+ print_output(selected_data, "pretty")
267
+ except Exception as e:
268
+ logger.error(f"Error fetching all devices: {e}")
269
+ typer.echo(f"Error fetching all devices: {e}")
270
+ raise typer.Exit(code=1)
271
+
272
+
273
+ if __name__ == "__main__":
274
+ app()
@@ -0,0 +1,79 @@
1
+ # “Commons Clause” License Condition v1.0
2
+ #
3
+ # The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition.
4
+ #
5
+ # Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, the right to Sell the Software.
6
+ #
7
+ # For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Clause License Condition notice.
8
+ #
9
+ # Software: pymbrewclient
10
+ # License: MIT License
11
+ # Licensor: Stuart Pearson
12
+ #
13
+ #
14
+ # MIT License
15
+ #
16
+ # Copyright (c) 2024 Stuart Pearson
17
+ #
18
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
19
+ # of this software and associated documentation files (the "Software"), to deal
20
+ # in the Software without restriction, including without limitation the rights
21
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22
+ # copies of the Software, and to permit persons to whom the Software is
23
+ # furnished to do so, subject to the following conditions:
24
+ #
25
+ # The above copyright notice and this permission notice shall be included in all
26
+ # copies or substantial portions of the Software.
27
+ #
28
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34
+ # SOFTWARE.
35
+ #
36
+ # Disclaimer: This software is an independent project and is not affiliated with, endorsed by, or associated with MiniBrew. MiniBrew's trademarks, logos, API, and other intellectual property are owned by MiniBrew and are not included in this software. Users are responsible for complying with MiniBrew's terms of service when using this software.from pymbrewclient.rest.client import RestApiClient
37
+ from pymbrewclient.rest.client import RestApiClient
38
+ from pymbrewclient.rest.models import TokenResponse, BreweryOverview, Session
39
+
40
+
41
+ class pymbrewclient:
42
+ """
43
+ A client for interacting with the Minibrew Pro Portal API.
44
+ """
45
+
46
+ def __init__(self, username: str, password: str, base_url: str = "https://api.minibrew.io") -> None:
47
+ """
48
+ Initialize the client with the base URL and user credentials.
49
+
50
+ :param base_url: The base URL for the API.
51
+ :param username: The username for authentication.
52
+ :param password: The password for authentication.
53
+ """
54
+ self.client = RestApiClient(base_url=base_url, username=username, password=password)
55
+
56
+ def get_token(self) -> TokenResponse:
57
+ """
58
+ Fetch and return the authentication token.
59
+
60
+ :return: A TokenResponse object containing the token and expiry time.
61
+ """
62
+ return self.client._get_token()
63
+
64
+ def get_brewery_overview(self) -> BreweryOverview:
65
+ """
66
+ Fetch and return the brewery overview.
67
+
68
+ :return: A BreweryOverview object containing the overview data.
69
+ """
70
+ return self.client.get_brewery_overview()
71
+
72
+ def get_session_info(self, sessionid: int) -> Session:
73
+ """
74
+ Fetch and return session information for a given session ID.
75
+
76
+ :param sessionid: The session ID to fetch information for.
77
+ :return: A Session object containing the session data.
78
+ """
79
+ return self.client.get_session_info(sessionid)
@@ -0,0 +1,36 @@
1
+ # “Commons Clause” License Condition v1.0
2
+ #
3
+ # The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition.
4
+ #
5
+ # Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, the right to Sell the Software.
6
+ #
7
+ # For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Clause License Condition notice.
8
+ #
9
+ # Software: pymbrewclient
10
+ # License: MIT License
11
+ # Licensor: Stuart Pearson
12
+ #
13
+ #
14
+ # MIT License
15
+ #
16
+ # Copyright (c) 2024 Stuart Pearson
17
+ #
18
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
19
+ # of this software and associated documentation files (the "Software"), to deal
20
+ # in the Software without restriction, including without limitation the rights
21
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22
+ # copies of the Software, and to permit persons to whom the Software is
23
+ # furnished to do so, subject to the following conditions:
24
+ #
25
+ # The above copyright notice and this permission notice shall be included in all
26
+ # copies or substantial portions of the Software.
27
+ #
28
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34
+ # SOFTWARE.
35
+ #
36
+ # Disclaimer: This software is an independent project and is not affiliated with, endorsed by, or associated with MiniBrew. MiniBrew's trademarks, logos, API, and other intellectual property are owned by MiniBrew and are not included in this software. Users are responsible for complying with MiniBrew's terms of service when using this software.
@@ -0,0 +1,163 @@
1
+ # “Commons Clause” License Condition v1.0
2
+ #
3
+ # The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition.
4
+ #
5
+ # Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, the right to Sell the Software.
6
+ #
7
+ # For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Clause License Condition notice.
8
+ #
9
+ # Software: pymbrewclient
10
+ # License: MIT License
11
+ # Licensor: Stuart Pearson
12
+ #
13
+ #
14
+ # MIT License
15
+ #
16
+ # Copyright (c) 2024 Stuart Pearson
17
+ #
18
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
19
+ # of this software and associated documentation files (the "Software"), to deal
20
+ # in the Software without restriction, including without limitation the rights
21
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22
+ # copies of the Software, and to permit persons to whom the Software is
23
+ # furnished to do so, subject to the following conditions:
24
+ #
25
+ # The above copyright notice and this permission notice shall be included in all
26
+ # copies or substantial portions of the Software.
27
+ #
28
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34
+ # SOFTWARE.
35
+ #
36
+ # Disclaimer: This software is an independent project and is not affiliated with, endorsed by, or associated with MiniBrew. MiniBrew's trademarks, logos, API, and other intellectual property are owned by MiniBrew and are not included in this software. Users are responsible for complying with MiniBrew's terms of service when using this software.import requests
37
+
38
+ from typing import Any
39
+ import requests
40
+ import time
41
+ from .models import TokenResponse, ApiResponse, BreweryOverview, Session
42
+ from loguru import logger
43
+
44
+
45
+ class RestApiClient:
46
+ def __init__(self, username: str, password: str, base_url: str, headers: dict[str, str] | None = None) -> None:
47
+ """
48
+ Initialize the REST API client for mbrewclient.
49
+
50
+ :param base_url: The base URL for the API.
51
+ :param username: The username for the Minibrew Pro Portal.
52
+ :param password: The password for the Minibrew Pro Portal.
53
+ """
54
+ self.base_url = base_url.rstrip("/")
55
+ self.username = username
56
+ self.password = password
57
+ self.headers = {"Client": "Breweryportal", "Content-Type": "application/json"}
58
+ self.token = None
59
+ self.token_expiry = 0
60
+
61
+ def _get_token(self) -> TokenResponse:
62
+ """
63
+ Obtain a new token using the username and password.
64
+
65
+ :return: A TokenResponse object containing the token and expiry time.
66
+ """
67
+ logger.debug("Fetching new token...")
68
+ url = "v2/token"
69
+ token_headers = self.headers.copy()
70
+ token_headers["Authorization"] = "TOKEN 4c433da015985d17669c604a5a4e2c906083e815"
71
+
72
+ response = self.post(
73
+ endpoint=url,
74
+ json={"email": self.username, "password": self.password},
75
+ headers=token_headers,
76
+ )
77
+ data = response.json()
78
+ self.token = data["token"]
79
+ self.token_expiry = time.time() + data["exp"]
80
+ self.headers["Authorization"] = f"Bearer {self.token}"
81
+
82
+ return TokenResponse(token=self.token, exp=data["exp"])
83
+
84
+ def _is_token_valid(self) -> bool:
85
+ """
86
+ Check if the current token is still valid.
87
+
88
+ :return: True if the token is valid, False otherwise.
89
+ """
90
+ if self.token is not None and time.time() < self.token_expiry:
91
+ return True
92
+ else:
93
+ logger.debug("Token is invalid or expired.")
94
+ return False
95
+
96
+ def _ensure_token(self) -> None:
97
+ """
98
+ Ensure a valid token is available. Renew if necessary.
99
+
100
+ :return: None
101
+ """
102
+ logger.debug("Ensuring token is valid...")
103
+ if not self._is_token_valid():
104
+ self._get_token()
105
+
106
+ def get(self, endpoint: str, params: dict[str, Any] | None = None, ensure_token: bool = True) -> ApiResponse:
107
+ """
108
+ Perform a GET request.
109
+
110
+ :param endpoint: The API endpoint (relative to the base URL).
111
+ :param params: Optional query parameters.
112
+ :return: An ApiResponse object containing the response data.
113
+ """
114
+ logger.debug(f"GET request to {endpoint} with params: {params}")
115
+ if ensure_token:
116
+ self._ensure_token()
117
+
118
+ url = f"{self.base_url}/{endpoint}/"
119
+ response = requests.get(url, params=params, headers=self.headers)
120
+ response.raise_for_status()
121
+ return response
122
+
123
+ def post(
124
+ self,
125
+ endpoint: str,
126
+ data: dict[str, Any] | None = None,
127
+ json: dict[str, Any] | None = None,
128
+ headers: dict[str, Any] | None = None,
129
+ ) -> requests.Response:
130
+ """
131
+ Perform a POST request.
132
+
133
+ :param endpoint: The API endpoint (relative to the base URL).
134
+ :param data: Optional form data to send in the body.
135
+ :param json: Optional JSON data to send in the body.
136
+ :return: The response object.
137
+ """
138
+ logger.debug(f"POST request to {endpoint} with data: {data}, json: {json}")
139
+ url = f"{self.base_url}/{endpoint}/"
140
+ response = requests.post(url, headers=headers, data=data, json=json)
141
+ response.raise_for_status()
142
+ return response
143
+
144
+ def get_brewery_overview(self) -> BreweryOverview:
145
+ """
146
+ Fetch the BreweryOverview from the API.
147
+
148
+ :return: A BreweryOverview object containing the brewery overview data.
149
+ """
150
+ logger.debug("Fetching brewery overview...")
151
+ response = self.get("v1/breweryoverview")
152
+ return BreweryOverview(**response.json())
153
+
154
+ def get_session_info(self, sessionid: int) -> Session:
155
+ """
156
+ Fetch session information from the API.
157
+
158
+ :param sessionid: The session ID to include in the query string.
159
+ :return: A Session object containing the session information.
160
+ """
161
+ logger.debug(f"Fetching session info for session ID: {sessionid}")
162
+ response = self.get(f"v1/sessions/{sessionid}")
163
+ return Session(**response.json())
@@ -0,0 +1,164 @@
1
+ # “Commons Clause” License Condition v1.0
2
+ #
3
+ # The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition.
4
+ #
5
+ # Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, the right to Sell the Software.
6
+ #
7
+ # For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Clause License Condition notice.
8
+ #
9
+ # Software: pymbrewclient
10
+ # License: MIT License
11
+ # Licensor: Stuart Pearson
12
+ #
13
+ #
14
+ # MIT License
15
+ #
16
+ # Copyright (c) 2024 Stuart Pearson
17
+ #
18
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
19
+ # of this software and associated documentation files (the "Software"), to deal
20
+ # in the Software without restriction, including without limitation the rights
21
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22
+ # copies of the Software, and to permit persons to whom the Software is
23
+ # furnished to do so, subject to the following conditions:
24
+ #
25
+ # The above copyright notice and this permission notice shall be included in all
26
+ # copies or substantial portions of the Software.
27
+ #
28
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34
+ # SOFTWARE.
35
+ #
36
+ # Disclaimer: This software is an independent project and is not affiliated with, endorsed by, or associated with MiniBrew. MiniBrew's trademarks, logos, API, and other intellectual property are owned by MiniBrew and are not included in this software. Users are responsible for complying with MiniBrew's terms of service when using this software.
37
+ from dataclasses import dataclass
38
+
39
+
40
+ @dataclass
41
+ class Device:
42
+ uuid: str
43
+ serial_number: str
44
+ device_type: int
45
+ user_action: int
46
+ process_type: int
47
+ title: str
48
+ sub_title: str
49
+ session_id: int | None
50
+ image: str
51
+ status_time: int | None
52
+ stage: str
53
+ beer_name: str | None
54
+ recipe_version: str | None
55
+ beer_style: str | None
56
+ gravity: str
57
+ target_temp: float | None
58
+ current_temp: float | None
59
+ online: bool
60
+ updating: bool
61
+ needs_acid_cleaning: bool
62
+ is_starting: bool | None
63
+ software_version: str
64
+
65
+
66
+ @dataclass
67
+ class BreweryOverview:
68
+ brew_clean_idle: list[Device]
69
+ fermenting: list[Device]
70
+ serving: list[Device]
71
+ brew_acid_clean_idle: list[Device]
72
+
73
+
74
+ @dataclass
75
+ class Beer:
76
+ id: int
77
+ name: str
78
+ image: str | None
79
+ style_name: str
80
+
81
+
82
+ @dataclass
83
+ class DeviceDetails:
84
+ uuid: str
85
+ serial_number: str
86
+ current_state: int
87
+ process_type: int
88
+ process_state: int
89
+ user_action: int
90
+ device_type: int
91
+ connection_status: int
92
+ last_time_online: str
93
+ software_version: str
94
+ custom_name: str
95
+
96
+
97
+ class Session:
98
+ def __init__(
99
+ self,
100
+ id: int,
101
+ profile: int,
102
+ beer: dict,
103
+ device: dict,
104
+ status: int,
105
+ session_type: int,
106
+ pending_command_seq: int,
107
+ pending_command_type: int,
108
+ pending_command_error: int,
109
+ beer_recipe_id: int,
110
+ beer_recipe_version: str,
111
+ brew_timestamp: float,
112
+ original_gravity: float,
113
+ timestamp_original_gravity: float,
114
+ is_brewpack: bool,
115
+ ) -> None:
116
+ self.id = id
117
+ self.profile = profile
118
+ self.beer = Beer(**beer) # Convert the beer dictionary into a Beer object
119
+ self.device = DeviceDetails(**device) # Convert the device dictionary into a DeviceDetails object
120
+ self.status = status
121
+ self.session_type = session_type
122
+ self.pending_command_seq = pending_command_seq
123
+ self.pending_command_type = pending_command_type
124
+ self.pending_command_error = pending_command_error
125
+ self.beer_recipe_id = beer_recipe_id
126
+ self.beer_recipe_version = beer_recipe_version
127
+ self.brew_timestamp = brew_timestamp
128
+ self.original_gravity = original_gravity
129
+ self.timestamp_original_gravity = timestamp_original_gravity
130
+ self.is_brewpack = is_brewpack
131
+
132
+ def __repr__(self) -> str:
133
+ return (
134
+ f"Session(\n"
135
+ f" id={self.id},\n"
136
+ f" profile={self.profile},\n"
137
+ f" beer={self.beer},\n"
138
+ f" device={self.device},\n"
139
+ f" status={self.status},\n"
140
+ f" session_type={self.session_type},\n"
141
+ f" pending_command_seq={self.pending_command_seq},\n"
142
+ f" pending_command_type={self.pending_command_type},\n"
143
+ f" pending_command_error={self.pending_command_error},\n"
144
+ f" beer_recipe_id={self.beer_recipe_id},\n"
145
+ f" beer_recipe_version={self.beer_recipe_version},\n"
146
+ f" brew_timestamp={self.brew_timestamp},\n"
147
+ f" original_gravity={self.original_gravity},\n"
148
+ f" timestamp_original_gravity={self.timestamp_original_gravity},\n"
149
+ f" is_brewpack={self.is_brewpack}\n"
150
+ f")"
151
+ )
152
+
153
+
154
+ @dataclass
155
+ class TokenResponse:
156
+ token: str
157
+ exp: int
158
+
159
+
160
+ @dataclass
161
+ class ApiResponse:
162
+ status_code: int
163
+ data: dict | None
164
+ message: str | None
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.4
2
+ Name: pymbrewclient
3
+ Version: 1.0.3
4
+ Summary: pymbrewclient: A Python library and CLI for readonly access to Minibrew's API
5
+ Author-email: Stuart Pearson <1926002+stuartp44@users.noreply.github.com>
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.10
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: pydantic<3,>=1.10.17
16
+ Requires-Dist: requests<3,>=2.32.3
17
+ Requires-Dist: loguru<1,>=0.7.2
18
+ Requires-Dist: typer<1,>=0.12.5
19
+ Requires-Dist: rich<14,>=13.9.4
20
+ Provides-Extra: dev
21
+ Requires-Dist: pytest<8,>=7.4.0; extra == "dev"
22
+ Requires-Dist: requests-mock<2,>=1.11.0; extra == "dev"
23
+ Requires-Dist: pytest-cov<5,>=4.1.0; extra == "dev"
24
+ Requires-Dist: black<24,>=23.9.1; extra == "dev"
25
+ Requires-Dist: Flask<3,>=2.3.3; extra == "dev"
26
+ Requires-Dist: ruff<1,>=0.7.2; extra == "dev"
27
+ Requires-Dist: pre-commit<5,>=4.0.1; extra == "dev"
28
+ Provides-Extra: build
29
+ Requires-Dist: build; extra == "build"
30
+ Requires-Dist: twine; extra == "build"
31
+ Dynamic: license-file
32
+
33
+ # pymbrewclient
34
+
35
+ `pymbrewclient` is a Python library and CLI tool for interacting with Minibrew's API. It provides both programmatic access and a command-line interface for fetching brewery and session information.
36
+
37
+ ---
38
+
39
+ ## Features
40
+
41
+ - Fetch brewery overview data.
42
+ - Retrieve session information.
43
+ - Easy-to-use CLI for quick access.
44
+ - Python library for programmatic integration.
45
+
46
+ ---
47
+
48
+ ### PLEASE NOTE
49
+ This library will only work with a valid subscription to the pro portal.
50
+
51
+ ## Installation
52
+
53
+ You can install `pymbrewclient` using `pip`:
54
+
55
+ ### CLI
56
+
57
+ ```bash
58
+ pip install pymbrewclient
59
+ ```
60
+
61
+ ```bash
62
+ pymbrewclient get-token --username <USERNAME> --password <PASSWORD>
63
+ ```
64
+
65
+ ```bash
66
+ pymbrewclient brewery-overview
67
+ ```
68
+
69
+ ```bash
70
+ pymbrewclient session-info --username <USERNAME> --password <PASSWORD> --session-id <SESSION_ID>
71
+ ```
72
+
73
+ ### Library Usage
74
+
75
+ ```python
76
+ from pymbrewclient import pymbrewclient
77
+
78
+ # Initialize the client
79
+ client = pymbrewclient(username,password)
80
+
81
+ # Fetch brewery overview
82
+ brewery_overview = client.get_brewery_overview()
83
+ print(brewery_overview)
84
+ ```
85
+
86
+ ```python
87
+ from pymbrewclient import pymbrewclient
88
+
89
+ # Initialize the client
90
+ client = pymbrewclient()
91
+
92
+ # Fetch session info
93
+ session_id = 12345
94
+ session_info = client.get_session_info(session_id)
95
+ print(session_info)
96
+ ```
97
+
98
+
99
+ ## Development
100
+
101
+ Clone the repository:
102
+ ```
103
+ git clone https://github.com/yourusername/pymbrewclient.git
104
+ cd pymbrewclient
105
+ ```
106
+
107
+ Install dependencies:
108
+ ```
109
+ pip install .[dev]
110
+ ```
111
+
112
+ Run tests:
113
+ ```
114
+ pytest
115
+ ```
116
+
117
+ Lint the code:
118
+ ```
119
+ make lint
120
+ ```
@@ -0,0 +1,12 @@
1
+ pymbrewclient/__init__.py,sha256=CYwZdlZaPG0qLmk2Wl4RK-iluTkW-XoMHPEr8JXDi9Y,2411
2
+ pymbrewclient/cli.py,sha256=WFd5Jyd69vtXgoE-ETJZJsGjXDFqEYy4Bo0gjojXPhI,11226
3
+ pymbrewclient/pymbrewclient.py,sha256=YYjPxFrCj4cJf9LEb47eCYD2ncUrsIO5_Xq4jc-yWGo,3981
4
+ pymbrewclient/rest/__init__.py,sha256=CYwZdlZaPG0qLmk2Wl4RK-iluTkW-XoMHPEr8JXDi9Y,2411
5
+ pymbrewclient/rest/client.py,sha256=wZJg-5SjstAG-G4ohE_WKyt6WhpziXYKhH8MXQNN9Cw,6955
6
+ pymbrewclient/rest/models.py,sha256=WM3x5H2Np9n8ocpgJUfrfH5h2G_ZN-ymFSQ5thwPups,5884
7
+ pymbrewclient-1.0.3.dist-info/licenses/LICENSE,sha256=R78D6QNQpdNRV58w-rVOzZ-2HrBBHZY5hg2POFxJYUs,2349
8
+ pymbrewclient-1.0.3.dist-info/METADATA,sha256=4q_pG9PHoeY781FSnO6vgw1JGjQi9hiNkle_X5jH1aY,2739
9
+ pymbrewclient-1.0.3.dist-info/WHEEL,sha256=ck4Vq1_RXyvS4Jt6SI0Vz6fyVs4GWg7AINwpsaGEgPE,91
10
+ pymbrewclient-1.0.3.dist-info/entry_points.txt,sha256=ywNMpadMTU-kFcbgQp25rlM1cbPLFaFwDIec0HKrK0A,56
11
+ pymbrewclient-1.0.3.dist-info/top_level.txt,sha256=u5AIf2yjh3UGeGGxgvafIuw7Vw9Bgz4oI75NVEMikdU,14
12
+ pymbrewclient-1.0.3.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ pymbrewclient = pymbrewclient.cli:app
@@ -0,0 +1,36 @@
1
+ “Commons Clause” License Condition v1.0
2
+
3
+ The Software is provided to you by the Licensor under the License, as defined below, subject to the following condition.
4
+
5
+ Without limiting other conditions in the License, the grant of rights under the License will not include, and the License does not grant to you, the right to Sell the Software.
6
+
7
+ For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you under the License to provide to third parties, for a fee or other consideration (including without limitation fees for hosting or consulting/ support services related to the Software), a product or service whose value derives, entirely or substantially, from the functionality of the Software. Any license notice or attribution required by the License must also include this Commons Clause License Condition notice.
8
+
9
+ Software: pymbrewclient
10
+ License: MIT License
11
+ Licensor: Stuart Pearson
12
+
13
+
14
+ MIT License
15
+
16
+ Copyright (c) 2024 Stuart Pearson
17
+
18
+ Permission is hereby granted, free of charge, to any person obtaining a copy
19
+ of this software and associated documentation files (the "Software"), to deal
20
+ in the Software without restriction, including without limitation the rights
21
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
22
+ copies of the Software, and to permit persons to whom the Software is
23
+ furnished to do so, subject to the following conditions:
24
+
25
+ The above copyright notice and this permission notice shall be included in all
26
+ copies or substantial portions of the Software.
27
+
28
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
29
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
30
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
31
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
32
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
33
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34
+ SOFTWARE.
35
+
36
+ Disclaimer: This software is an independent project and is not affiliated with, endorsed by, or associated with MiniBrew. MiniBrew's trademarks, logos, API, and other intellectual property are owned by MiniBrew and are not included in this software. Users are responsible for complying with MiniBrew's terms of service when using this software.
@@ -0,0 +1 @@
1
+ pymbrewclient