kiosker-python-api 1.2.1__py2.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.
kiosker/__init__.py ADDED
@@ -0,0 +1,2 @@
1
+ from .api import KioskerAPI
2
+ from .data import Status, Result, Blackout
kiosker/api.py ADDED
@@ -0,0 +1,103 @@
1
+ import httpx
2
+ from .data import Status, Result, Blackout, ScreensaverState
3
+
4
+ API_PATH = '/api/v1'
5
+
6
+ class KioskerAPI:
7
+ def __init__(self, host, token, port=8081, ssl=False):
8
+ if ssl:
9
+ self.conf_host = f'https://{host}:{port}'
10
+ else:
11
+ self.conf_host = f'http://{host}:{port}'
12
+
13
+ self.conf_headers = {'accept': 'application/json',
14
+ 'Authorization': f'Bearer {token}'}
15
+
16
+ def _get(self, path: str):
17
+ r = httpx.get(f'{self.conf_host}{API_PATH}{path}', headers=self.conf_headers)
18
+ if r.status_code == 200:
19
+ return r.json()
20
+ elif r.status_code == 401:
21
+ raise RuntimeError("Unauthorized")
22
+ elif r.status_code == 403:
23
+ raise RuntimeError("IP not allowed")
24
+ else:
25
+ r.raise_for_status()
26
+
27
+ def _post(self, path: str, json=None):
28
+ if json is None:
29
+ json = {}
30
+ r = httpx.post(f'{self.conf_host}{API_PATH}{path}', headers=self.conf_headers, json=json)
31
+ if r.status_code == 200:
32
+ return r.json()
33
+ elif r.status_code == 401:
34
+ raise RuntimeError("Unauthorized")
35
+ elif r.status_code == 403:
36
+ raise RuntimeError("IP not allowed")
37
+ elif r.status_code == 400:
38
+ raise RuntimeError("Bad request")
39
+ else:
40
+ r.raise_for_status()
41
+
42
+ def status(self):
43
+ status_data = self._get('/status').get('status')
44
+ return Status.from_dict(status_data)
45
+
46
+ def ping(self):
47
+ response_json = self._get('/ping')
48
+ result = Result.from_dict(response_json)
49
+ if result.error is False:
50
+ return True
51
+ else:
52
+ raise RuntimeError(f'Ping error: {result.reason}')
53
+
54
+ # Navigation
55
+ def navigate_home(self):
56
+ return Result.from_dict(self._post('/navigate/home'))
57
+
58
+ def navigate_refresh(self):
59
+ return Result.from_dict(self._post('/navigate/refresh'))
60
+
61
+ def navigate_forward(self):
62
+ return Result.from_dict(self._post('/navigate/forward'))
63
+
64
+ def navigate_backward(self):
65
+ return Result.from_dict(self._post('/navigate/backward'))
66
+
67
+ def navigate_url(self, url: str):
68
+ return Result.from_dict(self._post('/navigate/url', json={'url': url}))
69
+
70
+ # Print
71
+ def print(self):
72
+ return Result.from_dict(self._post('/print'))
73
+
74
+ # Clear
75
+ def clear_cookies(self):
76
+ return Result.from_dict(self._post('/clear/cookies'))
77
+
78
+ def clear_cache(self):
79
+ return Result.from_dict(self._post('/clear/cache'))
80
+
81
+ # Screensaver
82
+ def screensaver_interact(self):
83
+ return Result.from_dict(self._post('/screensaver/interact'))
84
+
85
+ def screensaver_set_disabled_state(self, disabled: bool):
86
+ return Result.from_dict(self._post('/screensaver/state', json={'disabled': disabled}))
87
+
88
+ def screensaver_get_state(self):
89
+ screensaver_status_data = self._get('/screensaver/state').get('screensaver')
90
+ return ScreensaverState.from_dict(screensaver_status_data)
91
+
92
+ # Blackout
93
+ def blackout_set(self, blackout: Blackout):
94
+ return Result.from_dict(self._post('/blackout', json=blackout.to_dict()))
95
+
96
+ def blackout_get(self):
97
+ blackout_data = self._get('/blackout/state').get('blackout')
98
+ if blackout_data is None:
99
+ return None
100
+ return Blackout.from_dict(blackout_data)
101
+
102
+ def blackout_clear(self):
103
+ return Result.from_dict(self._post('/blackout', json={'visible': False}))
kiosker/data.py ADDED
@@ -0,0 +1,84 @@
1
+ from dataclasses import dataclass, field
2
+ from datetime import datetime
3
+ from typing import Optional
4
+
5
+ @dataclass
6
+ class Status:
7
+ battery_level: int
8
+ battery_state: str
9
+ model: str
10
+ os_version: str
11
+ last_interaction: datetime
12
+ last_update: datetime
13
+ device_id: str
14
+ last_motion: Optional[datetime]
15
+ screensaver_pause: Optional[bool]
16
+
17
+ @classmethod
18
+ def from_dict(cls, status_data):
19
+ return cls(battery_level=status_data['batteryLevel'], battery_state=status_data['batteryState'], model=status_data['model'], os_version=status_data['osVersion'], last_interaction=datetime.fromisoformat(status_data['lastInteraction']), last_motion=datetime.fromisoformat(status_data['lastMotion']) if status_data.get('lastMotion') else None, last_update=datetime.fromisoformat(status_data['date']), device_id=status_data['deviceId'], screensaver_pause=status_data['screensaverPause'] if status_data.get('screensaverPause') else None)
20
+
21
+ @dataclass
22
+ class Result:
23
+ error: bool
24
+ reason: Optional[str]
25
+ function: Optional[str]
26
+
27
+ @classmethod
28
+ def from_dict(cls, result_data):
29
+ return cls(error=result_data['error'], reason=result_data['reason'] if result_data.get('reason') else None , function=result_data.get('function') if result_data.get('function') else None)
30
+
31
+ @dataclass
32
+ class ScreensaverState:
33
+ visible: bool
34
+ disabled: bool
35
+
36
+ @classmethod
37
+ def from_dict(cls, state_data):
38
+ return cls(visible=state_data['visible'], disabled=state_data['disabled'])
39
+
40
+
41
+ @dataclass
42
+ class Blackout:
43
+ visible: bool
44
+ background: Optional[str] = None
45
+ foreground: Optional[str] = None
46
+ expire: Optional[int] = None
47
+ text: Optional[str] = None
48
+ icon: Optional[str] = None
49
+ dismissible: Optional[bool] = False
50
+ buttonBackground: Optional[str] = None
51
+ buttonForeground: Optional[str] = None
52
+ buttonText: Optional[str] = None
53
+ sound: Optional[str] = None
54
+
55
+ def to_dict(self):
56
+ return {
57
+ 'visible': self.visible,
58
+ 'background': self.background,
59
+ 'foreground': self.foreground,
60
+ 'expire': self.expire,
61
+ 'text': self.text,
62
+ 'icon': self.icon,
63
+ 'dismissible': self.dismissible,
64
+ 'buttonBackground': self.buttonBackground,
65
+ 'buttonForeground': self.buttonForeground,
66
+ 'buttonText': self.buttonText,
67
+ 'sound': self.sound,
68
+ }
69
+
70
+ @classmethod
71
+ def from_dict(cls, blackout_data):
72
+ return cls(
73
+ visible=blackout_data['visible'],
74
+ background=blackout_data['background'],
75
+ foreground=blackout_data['foreground'],
76
+ expire=blackout_data['expire'],
77
+ text=blackout_data.get('text'),
78
+ icon=blackout_data.get('icon'),
79
+ dismissible=blackout_data.get('dismissible', False),
80
+ buttonBackground=blackout_data.get('buttonBackground'),
81
+ buttonForeground=blackout_data.get('buttonForeground'),
82
+ buttonText=blackout_data.get('buttonText'),
83
+ sound=blackout_data.get('sound'),
84
+ )
@@ -0,0 +1,261 @@
1
+ Metadata-Version: 2.4
2
+ Name: kiosker-python-api
3
+ Version: 1.2.1
4
+ Summary: A python wrapper for the Kiosker API
5
+ Project-URL: Homepage, https://kiosker.io
6
+ Project-URL: Documentation, https://docs.kiosker.io
7
+ Project-URL: Repository, https://github.com/Top-North/kiosker-python.git
8
+ Project-URL: Issues, https://github.com/Top-North/kiosker-python/issues
9
+ Author-email: Martin Claesson <martin@topnorth.se>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: api,kiosk,kiosker,kiosker pro
13
+ Requires-Dist: httpx
14
+ Provides-Extra: test
15
+ Requires-Dist: pytest; extra == 'test'
16
+ Description-Content-Type: text/markdown
17
+
18
+ # Python wrapper for Kiosker API
19
+ Python wrapper for Kiosker API-integration.
20
+
21
+ ---
22
+
23
+ ### Installation
24
+
25
+ ```shell
26
+ pip3 install kiosker-python
27
+ ```
28
+
29
+ ---
30
+
31
+ ### Setup
32
+
33
+ ```python
34
+ from kiosker.api import KioskerAPI
35
+ api = KioskerAPI('10.0.1.100', 'token')
36
+ ```
37
+
38
+ ---
39
+
40
+ ### Functions
41
+
42
+ #### Get Status
43
+ ```python
44
+ status = api.status()
45
+
46
+ print('Status:')
47
+ print(f'Device ID: {status.device_id}')
48
+ print(f'Model: {status.model}')
49
+ print(f'OS version: {status.os_version}')
50
+ print(f'Battery level: {status.battery_level}%')
51
+ print(f'Battery state: {status.battery_state}')
52
+ print(f'Last interaction: {status.last_interaction}')
53
+ print(f'Last motion: {status.last_motion}')
54
+ print(f'Last status update: {status.last_update}')
55
+ print(f'Screensaver pause: {status.screensaver_pause}')
56
+ ```
57
+ **Description**: Retrieves the current status of the kiosk.
58
+
59
+ #### Ping the API
60
+ ```python
61
+ result = api.ping()
62
+ print(f"Ping successful: {result}")
63
+ ```
64
+ **Description**: Checks if the API is reachable. Returns `True` if successful, otherwise raises an error.
65
+
66
+ #### Navigate to a URL
67
+ ```python
68
+ result = api.navigate_url('https://example.com')
69
+ print(f"Navigation result: {result}")
70
+ ```
71
+ **Description**: Navigates the kiosk to the specified URL.
72
+
73
+ #### Refresh the Page
74
+ ```python
75
+ result = api.navigate_refresh()
76
+ print(f"Refresh result: {result}")
77
+ ```
78
+ **Description**: Refreshes the current page on the kiosk.
79
+
80
+ #### Navigate Home
81
+ ```python
82
+ result = api.navigate_home()
83
+ print(f"Home navigation result: {result}")
84
+ ```
85
+ **Description**: Navigates the kiosk to the home page.
86
+
87
+ #### Navigate Forward
88
+ ```python
89
+ result = api.navigate_forward()
90
+ print(f"Navigate forward result: {result}")
91
+ ```
92
+ **Description**: Navigates forward in the browser's history.
93
+
94
+ #### Navigate Backward
95
+ ```python
96
+ result = api.navigate_backward()
97
+ print(f"Navigate backward result: {result}")
98
+ ```
99
+ **Description**: Navigates backward in the browser's history.
100
+
101
+ #### Print
102
+ ```python
103
+ result = api.print()
104
+ print(f"Print result: {result}")
105
+ ```
106
+ **Description**: Sends a print command to the kiosk.
107
+
108
+ #### Clear Cookies
109
+ ```python
110
+ result = api.clear_cookies()
111
+ print(f"Cookies cleared: {result}")
112
+ ```
113
+ **Description**: Clears all cookies stored on the kiosk.
114
+
115
+ #### Clear Cache
116
+ ```python
117
+ result = api.clear_cache()
118
+ print(f"Cache cleared: {result}")
119
+ ```
120
+ **Description**: Clears the cache on the kiosk.
121
+
122
+ #### Interact with Screensaver
123
+ ```python
124
+ result = api.screensaver_interact()
125
+ print(f"Screensaver interaction result: {result}")
126
+ ```
127
+ **Description**: Simulates user interaction with the screensaver to prevent it from activating.
128
+
129
+ #### Set Screensaver State
130
+ ```python
131
+ result = api.screensaver_set_state(disabled=True)
132
+ print(f"Screensaver disabled: {result}")
133
+ ```
134
+ **Description**: Enables or disables the screensaver.
135
+
136
+ #### Get Screensaver State
137
+ ```python
138
+ state = api.screensaver_get_state()
139
+ print(f"Screensaver state: {state}")
140
+ ```
141
+ **Description**: Retrieves the current state of the screensaver (enabled or disabled).
142
+
143
+ #### Set Blackout
144
+ ```python
145
+ from kiosker.data import Blackout
146
+
147
+ blackout = Blackout(
148
+ visible=True, # Required: show blackout screen
149
+ text="Maintenance in progress", # Optional: text to display
150
+ background="#000000", # Optional: background color (hex)
151
+ foreground="#FFFFFF", # Optional: foreground/text color (hex)
152
+ icon="warning", # Optional: icon name (SF Symbol)
153
+ expire=60, # Optional: time in seconds before blackout expires
154
+ dismissible=True, # Optional: allow user to dismiss blackout with a button
155
+ buttonBackground="#FF0000", # Optional: button background color (hex)
156
+ buttonForeground="#FFFFFF", # Optional: button text color (hex)
157
+ buttonText="OK", # Optional: button label
158
+ sound="1003" # Optional: sound to play (SystemSoundID)
159
+ )
160
+ result = api.blackout_set(blackout)
161
+ print(f"Blackout set: {result}")
162
+ ```
163
+ **Description**: Sets a blackout screen with customizable text, colors, expiration time, and optional button/sound options.
164
+
165
+ #### Get Blackout State
166
+ ```python
167
+ blackout_state = api.blackout_get()
168
+ print(f"Blackout state: {blackout_state}")
169
+ ```
170
+ **Description**: Retrieves the current state of the blackout screen.
171
+
172
+ #### Clear Blackout
173
+ ```python
174
+ result = api.blackout_clear()
175
+ print(f"Blackout cleared: {result}")
176
+ ```
177
+ **Description**: Clears the blackout screen.
178
+
179
+ ---
180
+
181
+ ### Objects
182
+
183
+ #### `Status`
184
+ Represents the current status of the kiosk.
185
+
186
+ **Attributes**:
187
+ - `battery_level` (int): Battery percentage.
188
+ - `battery_state` (str): Current battery state (e.g., charging, discharging).
189
+ - `model` (str): Device model.
190
+ - `os_version` (str): Operating system version.
191
+ - `last_interaction` (datetime): Timestamp of the last user interaction.
192
+ - `last_motion` (Optional[datetime]): Timestamp of the last detected motion.
193
+ - `last_update` (datetime): Timestamp of the last status update.
194
+ - `device_id` (str): Unique identifier for the device.
195
+ - `screensaver_pause` (Optional[bool]): Whether the screensaver is paused.
196
+
197
+ #### `Result`
198
+ Represents the result of an API operation.
199
+
200
+ **Attributes**:
201
+ - `error` (bool): Indicates if an error occurred.
202
+ - `reason` (Optional[str]): Reason for the error, if any.
203
+ - `function` (Optional[str]): Name of the function that caused the error.
204
+
205
+ #### `Blackout`
206
+ Represents a blackout screen configuration.
207
+
208
+ **Attributes**:
209
+ - `visible` (bool): Whether the blackout screen is visible.
210
+ - `text` (Optional[str]): Text to display on the blackout screen.
211
+ - `background` (str): Background color in hex format.
212
+ - `foreground` (str): Foreground color in hex format.
213
+ - `icon` (Optional[str]): Icon to display on the blackout screen.
214
+ - `expire` (int): Time in seconds before the blackout screen expires.
215
+
216
+ ---
217
+
218
+ ### Development
219
+ 1. Clone the project
220
+
221
+ 2. Create a virtual environment
222
+ ```shell
223
+ python3 -m venv venv
224
+ ```
225
+
226
+ 3. Activate the virtual environment
227
+ ```shell
228
+ source venv/bin/activate
229
+ ```
230
+
231
+ 4. Install dependencies
232
+ ```shell
233
+ pip install wheel setuptools twine pytest httpx
234
+ ```
235
+
236
+ 5. Run tests
237
+ ```shell
238
+ HOST="0.0.0.0" TOKEN="" pytest -s
239
+ ```
240
+
241
+ 6. Build the library
242
+ ```shell
243
+ python -m build --wheel
244
+ ```
245
+
246
+ 7. Upload to test
247
+ ```shell
248
+ twine upload --repository testpypi dist/*
249
+ ```
250
+
251
+ ---
252
+
253
+ ### API Documentation
254
+ - [Docs](https://docs.kiosker.io/#/api)
255
+ - [Definition](https://swagger.kiosker.io)
256
+
257
+ ---
258
+
259
+ ### Get Kiosker for iOS on the App Store
260
+ - [Kiosker](https://apps.apple.com/us/app/kiosker-fullscreen-web-kiosk/id1481691530?uo=4&at=11l6hc&ct=fnd)
261
+ - [Kiosker Pro](https://apps.apple.com/us/app/kiosker-pro-web-kiosk/id1446738885?uo=4&at=11l6hc&ct=fnd)
@@ -0,0 +1,7 @@
1
+ kiosker/__init__.py,sha256=2IUwkYlNimXNczxs09J33WoNGdRTEDFD23VtYl6TDg4,70
2
+ kiosker/api.py,sha256=bqa5UWzZbFXYb34dev71jCb2SfHmNS0CU66cikrlLuE,3561
3
+ kiosker/data.py,sha256=ku8monJFlLxR4RQpqA18NituZRuNSDVFbYyAE85AY7Q,3114
4
+ kiosker_python_api-1.2.1.dist-info/METADATA,sha256=2EQ3rsW45s8RSO4g5f5-5ksXnqPUd6TdoF1oIBgVYhY,7140
5
+ kiosker_python_api-1.2.1.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
6
+ kiosker_python_api-1.2.1.dist-info/licenses/LICENSE,sha256=mjD-_yvrBLGI96FVJteQTq936wbgJmFImKQ2Het_8HQ,1069
7
+ kiosker_python_api-1.2.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py2-none-any
5
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Top North AB
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.