boneIO 0.1.0.dev5__tar.gz → 0.1.0.dev7__tar.gz
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.
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/PKG-INFO +2 -2
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/bonecli.py +5 -1
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/helper/stats.py +48 -1
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/manager.py +18 -5
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/mqtt_client.py +1 -3
- boneio-0.1.0.dev7/boneio/oled.py +82 -0
- boneio-0.1.0.dev7/boneio/version.py +2 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio.egg-info/PKG-INFO +2 -2
- boneio-0.1.0.dev5/boneio/oled.py +0 -120
- boneio-0.1.0.dev5/boneio/version.py +0 -2
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/MANIFEST.in +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/README.md +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/__init__.py +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/config.example.yaml +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/config.yaml +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/const.py +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/helper/__init__.py +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/helper/gpio.py +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/helper/yaml.py +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/input/__init__.py +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/input/gpio.py +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/relay/__init__.py +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/relay/basic.py +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/relay/gpio.py +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/relay/mcp.py +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio/schema.yaml +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio.egg-info/SOURCES.txt +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio.egg-info/dependency_links.txt +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio.egg-info/entry_points.txt +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio.egg-info/requires.txt +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/boneio.egg-info/top_level.txt +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/requirements.txt +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/setup.cfg +0 -0
- {boneio-0.1.0.dev5 → boneio-0.1.0.dev7}/setup.py +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: boneio
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev7
|
|
4
4
|
Summary: Python Helper for BoneIO
|
|
5
5
|
Home-page: https://github.com/maciejk1984/boneIO
|
|
6
6
|
License: GNU General Public License v3.0
|
|
7
|
-
Download-URL: https://github.com/maciejk1984/boneIO/archive/0.1.0.
|
|
7
|
+
Download-URL: https://github.com/maciejk1984/boneIO/archive/0.1.0.dev7.zip
|
|
8
8
|
Platform: UNKNOWN
|
|
9
9
|
Classifier: Programming Language :: Python
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.7
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from .helper import CustomValidator, load_yaml_file
|
|
2
2
|
import click
|
|
3
3
|
import logging
|
|
4
|
+
from contextlib import AsyncExitStack
|
|
4
5
|
from colorlog import ColoredFormatter
|
|
5
6
|
from .mqtt_client import MQTTClient
|
|
6
7
|
from .manager import Manager
|
|
@@ -136,7 +137,10 @@ async def run(ctx, debug: int, config: str, mqttpassword: str = ""):
|
|
|
136
137
|
mcp23017=_config[MCP23017],
|
|
137
138
|
oled=_config.get(OLED),
|
|
138
139
|
)
|
|
139
|
-
|
|
140
|
+
tasks = set()
|
|
141
|
+
tasks.add(client.start_client(manager))
|
|
142
|
+
tasks.update(manager.get_tasks())
|
|
143
|
+
await asyncio.gather(*tasks)
|
|
140
144
|
|
|
141
145
|
|
|
142
146
|
if __name__ == "__main__":
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import psutil
|
|
3
3
|
from math import floor
|
|
4
|
-
from ..const import
|
|
4
|
+
from ..const import (
|
|
5
|
+
GIGABYTE,
|
|
6
|
+
MEGABYTE,
|
|
7
|
+
NETWORK,
|
|
8
|
+
DISK,
|
|
9
|
+
MEMORY,
|
|
10
|
+
CPU,
|
|
11
|
+
SWAP,
|
|
12
|
+
UPTIME,
|
|
13
|
+
HOST,
|
|
14
|
+
OUTPUT,
|
|
15
|
+
OledDataTypes,
|
|
16
|
+
)
|
|
5
17
|
import time
|
|
6
18
|
|
|
7
19
|
intervals = (
|
|
@@ -113,3 +125,38 @@ host_stats = {
|
|
|
113
125
|
SWAP: get_swap_info,
|
|
114
126
|
UPTIME: get_uptime,
|
|
115
127
|
}
|
|
128
|
+
|
|
129
|
+
import socket
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class HostData:
|
|
133
|
+
"""Helper class to store host data."""
|
|
134
|
+
|
|
135
|
+
data = {UPTIME: {}, NETWORK: {}, CPU: {}, DISK: {}, MEMORY: {}, SWAP: {}}
|
|
136
|
+
|
|
137
|
+
def __init__(self, output: dict) -> None:
|
|
138
|
+
"""Initialize HostData."""
|
|
139
|
+
self._hostname = socket.gethostname()
|
|
140
|
+
self.data[UPTIME] = {HOST: self._hostname, UPTIME: 0}
|
|
141
|
+
self._output = output
|
|
142
|
+
|
|
143
|
+
def write(self, type: str, data: dict) -> None:
|
|
144
|
+
"""Write data of chosen type."""
|
|
145
|
+
self.data[type] = data
|
|
146
|
+
|
|
147
|
+
def write_uptime(self, uptime: str) -> None:
|
|
148
|
+
"""Write uptime."""
|
|
149
|
+
self.data[UPTIME][UPTIME] = uptime
|
|
150
|
+
|
|
151
|
+
def get(self, type: OledDataTypes) -> dict:
|
|
152
|
+
"""Get saved stats."""
|
|
153
|
+
if type == OUTPUT:
|
|
154
|
+
return self._get_output()
|
|
155
|
+
return self.data[type]
|
|
156
|
+
|
|
157
|
+
def _get_output(self) -> dict:
|
|
158
|
+
"""Get stats for output."""
|
|
159
|
+
out = {}
|
|
160
|
+
for output in self._output.values():
|
|
161
|
+
out[output.id] = output.state
|
|
162
|
+
return out
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
from .input import GpioInputButton
|
|
2
2
|
from .relay import GpioRelay, MCPRelay
|
|
3
3
|
from .oled import Oled
|
|
4
|
+
from .helper.stats import host_stats, HostData
|
|
5
|
+
from typing import Set
|
|
6
|
+
import asyncio
|
|
7
|
+
import logging
|
|
8
|
+
|
|
4
9
|
from .const import (
|
|
5
10
|
ACTION,
|
|
11
|
+
OUTPUT,
|
|
6
12
|
ACTIONS,
|
|
7
13
|
ADDRESS,
|
|
8
14
|
GPIO,
|
|
@@ -64,9 +70,11 @@ class Manager:
|
|
|
64
70
|
ha_discovery_prefix: str = "homeassistant",
|
|
65
71
|
mcp23017: Optional[List] = None,
|
|
66
72
|
oled: bool = False,
|
|
73
|
+
web: bool = False,
|
|
67
74
|
) -> None:
|
|
68
75
|
"""Initialize the manager."""
|
|
69
76
|
loop = asyncio.get_event_loop()
|
|
77
|
+
self._host_data = None
|
|
70
78
|
|
|
71
79
|
self.send_message = send_message
|
|
72
80
|
self._topic_prefix = topic_prefix
|
|
@@ -75,6 +83,7 @@ class Manager:
|
|
|
75
83
|
self._i2cbusio = I2C(SCL, SDA)
|
|
76
84
|
self._mcp = {}
|
|
77
85
|
self._oled = None
|
|
86
|
+
self._tasks: List[asyncio.Task] = []
|
|
78
87
|
|
|
79
88
|
if mcp23017:
|
|
80
89
|
for mcp in mcp23017:
|
|
@@ -127,15 +136,19 @@ class Manager:
|
|
|
127
136
|
for gpio in self._input_pins
|
|
128
137
|
]
|
|
129
138
|
|
|
139
|
+
if oled or web:
|
|
140
|
+
self._host_data = HostData(output=self.output)
|
|
141
|
+
for f in host_stats.values():
|
|
142
|
+
self._tasks.append(asyncio.create_task(f(self._host_data)))
|
|
143
|
+
|
|
130
144
|
if oled:
|
|
131
|
-
self._oled = Oled(self.
|
|
145
|
+
self._oled = Oled(self._host_data)
|
|
146
|
+
self._tasks.append(self._oled.get_task())
|
|
132
147
|
|
|
133
148
|
self.send_message(topic=f"{topic_prefix}/{STATE}", payload=ONLINE)
|
|
134
149
|
|
|
135
|
-
def
|
|
136
|
-
|
|
137
|
-
return []
|
|
138
|
-
return self._oled.get_tasks()
|
|
150
|
+
def get_tasks(self) -> Set[asyncio.Task]:
|
|
151
|
+
return self._tasks
|
|
139
152
|
|
|
140
153
|
def press_callback(self, x: ClickTypes, inpin: str, actions: dict) -> None:
|
|
141
154
|
"""Press callback to use in input gpio.
|
|
@@ -144,7 +144,7 @@ class MQTTClient:
|
|
|
144
144
|
self.create_client() # reset connect/reconnect futures
|
|
145
145
|
|
|
146
146
|
async def _subscribe_manager(self, manager: any) -> None:
|
|
147
|
-
"""Connect and subscribe to manager topics."""
|
|
147
|
+
"""Connect and subscribe to manager topics + host stats."""
|
|
148
148
|
async with AsyncExitStack() as stack:
|
|
149
149
|
tasks: Set[asyncio.Task] = set()
|
|
150
150
|
|
|
@@ -166,8 +166,6 @@ class MQTTClient:
|
|
|
166
166
|
)
|
|
167
167
|
tasks.add(messages_task)
|
|
168
168
|
|
|
169
|
-
tasks.update(manager.get_oled_tasks())
|
|
170
|
-
|
|
171
169
|
topic = f"{manager.relay_topic}"
|
|
172
170
|
await self.subscribe(topic)
|
|
173
171
|
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from .helper.gpio import setup_input, edge_detect
|
|
2
|
+
from .helper.stats import HostData
|
|
3
|
+
from .input.gpio import configure_pin
|
|
4
|
+
from .const import (
|
|
5
|
+
OLED_PIN,
|
|
6
|
+
NETWORK,
|
|
7
|
+
CPU,
|
|
8
|
+
DISK,
|
|
9
|
+
MEMORY,
|
|
10
|
+
SWAP,
|
|
11
|
+
NUM_OF_SCREENS,
|
|
12
|
+
UPTIME,
|
|
13
|
+
OUTPUT,
|
|
14
|
+
WHITE,
|
|
15
|
+
)
|
|
16
|
+
import asyncio
|
|
17
|
+
import os
|
|
18
|
+
import logging
|
|
19
|
+
|
|
20
|
+
from luma.core.interface.serial import i2c
|
|
21
|
+
from luma.core.render import canvas
|
|
22
|
+
from luma.oled.device import sh1106
|
|
23
|
+
from PIL import ImageFont
|
|
24
|
+
|
|
25
|
+
_LOGGER = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def make_font(name, size):
|
|
29
|
+
font_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "fonts", name))
|
|
30
|
+
return ImageFont.truetype(font_path, size)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
fontBig = make_font("DejaVuSans.ttf", 12)
|
|
34
|
+
fontSmall = make_font("DejaVuSans.ttf", 10)
|
|
35
|
+
|
|
36
|
+
screen_order = [UPTIME, NETWORK, CPU, DISK, MEMORY, SWAP, OUTPUT]
|
|
37
|
+
lines = [17, 32, 47]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class Oled:
|
|
41
|
+
"""Oled display class."""
|
|
42
|
+
|
|
43
|
+
def __init__(self, host_data: HostData) -> None:
|
|
44
|
+
"""Initialize OLED screen."""
|
|
45
|
+
self._screen_no = 0
|
|
46
|
+
self._loop = asyncio.get_running_loop()
|
|
47
|
+
self._host_data = host_data
|
|
48
|
+
configure_pin(OLED_PIN)
|
|
49
|
+
setup_input(OLED_PIN)
|
|
50
|
+
edge_detect(OLED_PIN, callback=self._handle_press, bounce=50)
|
|
51
|
+
serial = i2c(port=2, address=0x3C)
|
|
52
|
+
self._device = sh1106(serial)
|
|
53
|
+
_LOGGER.debug("Configuring OLED screen.")
|
|
54
|
+
|
|
55
|
+
def get_task(self) -> list:
|
|
56
|
+
"""Periodically check for host statistics."""
|
|
57
|
+
return asyncio.create_task(self.render_display())
|
|
58
|
+
|
|
59
|
+
async def render_display(self):
|
|
60
|
+
while True:
|
|
61
|
+
screen = screen_order[self._screen_no]
|
|
62
|
+
data = self._host_data.get(screen)
|
|
63
|
+
if data:
|
|
64
|
+
with canvas(self._device) as draw:
|
|
65
|
+
draw.text((1, 1), screen, font=fontBig, fill=WHITE)
|
|
66
|
+
i = 0
|
|
67
|
+
for k in data:
|
|
68
|
+
draw.text(
|
|
69
|
+
(3, lines[i]),
|
|
70
|
+
f"{k} {data[k]}",
|
|
71
|
+
font=fontSmall,
|
|
72
|
+
fill=WHITE,
|
|
73
|
+
)
|
|
74
|
+
i += 1
|
|
75
|
+
await asyncio.sleep(0.5)
|
|
76
|
+
|
|
77
|
+
def _handle_press(self, pin: any) -> None:
|
|
78
|
+
"""Handle press of PIN for OLED display."""
|
|
79
|
+
if self._screen_no < NUM_OF_SCREENS:
|
|
80
|
+
self._screen_no += 1
|
|
81
|
+
else:
|
|
82
|
+
self._screen_no = 0
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: boneio
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev7
|
|
4
4
|
Summary: Python Helper for BoneIO
|
|
5
5
|
Home-page: https://github.com/maciejk1984/boneIO
|
|
6
6
|
License: GNU General Public License v3.0
|
|
7
|
-
Download-URL: https://github.com/maciejk1984/boneIO/archive/0.1.0.
|
|
7
|
+
Download-URL: https://github.com/maciejk1984/boneIO/archive/0.1.0.dev7.zip
|
|
8
8
|
Platform: UNKNOWN
|
|
9
9
|
Classifier: Programming Language :: Python
|
|
10
10
|
Classifier: Programming Language :: Python :: 3.7
|
boneio-0.1.0.dev5/boneio/oled.py
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
from .helper.gpio import setup_input, edge_detect
|
|
2
|
-
from .helper.stats import host_stats
|
|
3
|
-
from .input.gpio import configure_pin
|
|
4
|
-
from .const import (
|
|
5
|
-
OLED_PIN,
|
|
6
|
-
NETWORK,
|
|
7
|
-
CPU,
|
|
8
|
-
DISK,
|
|
9
|
-
MEMORY,
|
|
10
|
-
SWAP,
|
|
11
|
-
NUM_OF_SCREENS,
|
|
12
|
-
UPTIME,
|
|
13
|
-
HOST,
|
|
14
|
-
OUTPUT,
|
|
15
|
-
WHITE,
|
|
16
|
-
OledDataTypes,
|
|
17
|
-
)
|
|
18
|
-
import asyncio
|
|
19
|
-
import os
|
|
20
|
-
import socket
|
|
21
|
-
import logging
|
|
22
|
-
|
|
23
|
-
from functools import partial
|
|
24
|
-
from luma.core.interface.serial import i2c
|
|
25
|
-
from luma.core.render import canvas
|
|
26
|
-
from luma.oled.device import sh1106
|
|
27
|
-
from PIL import ImageFont
|
|
28
|
-
|
|
29
|
-
_LOGGER = logging.getLogger(__name__)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def make_font(name, size):
|
|
33
|
-
font_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "fonts", name))
|
|
34
|
-
return ImageFont.truetype(font_path, size)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
fontBig = make_font("DejaVuSans.ttf", 12)
|
|
38
|
-
fontSmall = make_font("DejaVuSans.ttf", 10)
|
|
39
|
-
|
|
40
|
-
screen_order = [UPTIME, NETWORK, CPU, DISK, MEMORY, SWAP, OUTPUT]
|
|
41
|
-
lines = [17, 32, 47]
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
class HostData:
|
|
45
|
-
"""Helper class to store host data."""
|
|
46
|
-
|
|
47
|
-
data = {UPTIME: {}, NETWORK: {}, CPU: {}, DISK: {}, MEMORY: {}, SWAP: {}}
|
|
48
|
-
|
|
49
|
-
def __init__(self, output: dict) -> None:
|
|
50
|
-
"""Initialize HostData."""
|
|
51
|
-
self._hostname = socket.gethostname()
|
|
52
|
-
self.data[UPTIME] = {HOST: self._hostname, UPTIME: 0}
|
|
53
|
-
self._output = output
|
|
54
|
-
|
|
55
|
-
def write(self, type: str, data: dict) -> None:
|
|
56
|
-
"""Write data of chosen type."""
|
|
57
|
-
self.data[type] = data
|
|
58
|
-
|
|
59
|
-
def write_uptime(self, uptime: str) -> None:
|
|
60
|
-
"""Write uptime."""
|
|
61
|
-
self.data[UPTIME][UPTIME] = uptime
|
|
62
|
-
|
|
63
|
-
def get(self, type: OledDataTypes) -> dict:
|
|
64
|
-
"""Get saved stats."""
|
|
65
|
-
if type == OUTPUT:
|
|
66
|
-
return self._get_output()
|
|
67
|
-
return self.data[type]
|
|
68
|
-
|
|
69
|
-
def _get_output(self) -> dict:
|
|
70
|
-
"""Get stats for output."""
|
|
71
|
-
out = {}
|
|
72
|
-
for output in self._output.values():
|
|
73
|
-
out[output.id] = output.state
|
|
74
|
-
return out
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
class Oled:
|
|
78
|
-
"""Oled display class."""
|
|
79
|
-
|
|
80
|
-
def __init__(self, output: dict) -> None:
|
|
81
|
-
"""Initialize OLED screen."""
|
|
82
|
-
self._screen_no = 0
|
|
83
|
-
self._loop = asyncio.get_running_loop()
|
|
84
|
-
self._host_data = HostData(output=output)
|
|
85
|
-
configure_pin(OLED_PIN)
|
|
86
|
-
setup_input(OLED_PIN)
|
|
87
|
-
edge_detect(OLED_PIN, callback=self._handle_press, bounce=50)
|
|
88
|
-
serial = i2c(port=2, address=0x3C)
|
|
89
|
-
self._device = sh1106(serial)
|
|
90
|
-
_LOGGER.debug("Configuring OLED screen.")
|
|
91
|
-
|
|
92
|
-
def get_tasks(self) -> list:
|
|
93
|
-
"""Periodically check for host statistics."""
|
|
94
|
-
return [
|
|
95
|
-
asyncio.create_task(func(self._host_data)) for func in host_stats.values()
|
|
96
|
-
]
|
|
97
|
-
|
|
98
|
-
def _handle_press(self, pin: any) -> None:
|
|
99
|
-
"""Handle press of PIN for OLED display."""
|
|
100
|
-
|
|
101
|
-
def press_callback(screen_no):
|
|
102
|
-
screen = screen_order[screen_no]
|
|
103
|
-
data = self._host_data.get(screen)
|
|
104
|
-
with canvas(self._device) as draw:
|
|
105
|
-
draw.text((1, 1), screen, font=fontBig, fill=WHITE)
|
|
106
|
-
i = 0
|
|
107
|
-
for k in data:
|
|
108
|
-
draw.text(
|
|
109
|
-
(3, lines[i]),
|
|
110
|
-
f"{k} {data[k]}",
|
|
111
|
-
font=fontSmall,
|
|
112
|
-
fill=WHITE,
|
|
113
|
-
)
|
|
114
|
-
i += 1
|
|
115
|
-
|
|
116
|
-
self._loop.call_soon_threadsafe(partial(press_callback, self._screen_no))
|
|
117
|
-
if self._screen_no < NUM_OF_SCREENS:
|
|
118
|
-
self._screen_no += 1
|
|
119
|
-
else:
|
|
120
|
-
self._screen_no = 0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|