refactor devices model, improve lightstrip
This commit is contained in:
parent
3434fb8f96
commit
da825c1564
|
@ -104,6 +104,13 @@ async def new_device(request, ws, data):
|
|||
|
||||
if device_type == 'RelayDevice':
|
||||
device = models.RelayDevice()
|
||||
device.sub_devices.append(models.RelayOutlet())
|
||||
device.sub_devices.append(models.RelayOutlet())
|
||||
device.sub_devices[0].id = 'OUT0'
|
||||
device.sub_devices[0].gpio = '0'
|
||||
device.sub_devices[1].id = 'OUT2'
|
||||
device.sub_devices[1].gpio = '2'
|
||||
device.update()
|
||||
else:
|
||||
data['ok'] = False
|
||||
data['error'] = "unknown device type"
|
||||
|
|
19
juice.py
19
juice.py
|
@ -29,6 +29,8 @@ async def index(request):
|
|||
"""The index page."""
|
||||
init_state = {}
|
||||
for device in network:
|
||||
if device.type != "RelayDevice":
|
||||
continue
|
||||
device_state = {}
|
||||
for sub_dev in device.sub_devices:
|
||||
device_state[sub_dev.id] = sub_dev.state
|
||||
|
@ -64,6 +66,14 @@ async def websocket_handler(request):
|
|||
return ws
|
||||
|
||||
|
||||
def html_color(color):
|
||||
"""Converts a decimal color code to HTML format."""
|
||||
html_color = "#"
|
||||
for i in range(3):
|
||||
html_color += hex(color[i])[2:].zfill(2)
|
||||
return html_color
|
||||
|
||||
|
||||
async def send_json_all(self, d):
|
||||
"""Sends to all connected websockets."""
|
||||
for ws in self['websockets']:
|
||||
|
@ -74,7 +84,14 @@ async def init_app():
|
|||
"""Initializes the application."""
|
||||
web.Application.send_json_all = send_json_all
|
||||
app = web.Application(middlewares=[buckler_aiohttp.buckler_session])
|
||||
aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader('templates'))
|
||||
aiohttp_jinja2.setup(
|
||||
app,
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True,
|
||||
undefined=jinja2.StrictUndefined,
|
||||
loader=jinja2.FileSystemLoader('templates'),
|
||||
filters={'html_color': html_color},
|
||||
)
|
||||
app['websockets'] = []
|
||||
|
||||
app.router.add_routes(routes)
|
||||
|
|
115
models.py
115
models.py
|
@ -28,6 +28,15 @@ class Device:
|
|||
"""
|
||||
Represents a generic device on the Network.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.id = ""
|
||||
self.type = ""
|
||||
self.description = ""
|
||||
self.location = ""
|
||||
self.ip_address = ""
|
||||
self.locked = False
|
||||
self.sub_devices = []
|
||||
|
||||
def find(self, sub_device_id):
|
||||
"""
|
||||
Searches through the devices sub_devices and returns the matching
|
||||
|
@ -40,6 +49,40 @@ class Device:
|
|||
return None
|
||||
return sub_device
|
||||
|
||||
def from_dict(self, data):
|
||||
"""
|
||||
Initializes self with data from dict.
|
||||
"""
|
||||
for key, value in data.items():
|
||||
if key == 'sub_devices':
|
||||
continue
|
||||
else:
|
||||
setattr(self, key, value)
|
||||
for sub_device_dict in data.get('sub_devices'):
|
||||
if sub_device_dict.get('type') == 'RelayOutlet':
|
||||
sub_device = RelayOutlet().from_dict(sub_device_dict)
|
||||
self.sub_devices.append(sub_device)
|
||||
elif sub_device_dict.get('type') == 'NeoPixel':
|
||||
sub_device = NeoPixel().from_dict(sub_device_dict)
|
||||
self.sub_devices.append(sub_device)
|
||||
else:
|
||||
typ = sub_device_dict.get('type')
|
||||
raise ValueError(f"Unknown sub_device type {typ}")
|
||||
return self
|
||||
|
||||
|
||||
class SubDevice:
|
||||
"""
|
||||
Represents a generic subdevice in a Device.
|
||||
"""
|
||||
def from_dict(self, data):
|
||||
"""
|
||||
Initializes self with data from dict.
|
||||
"""
|
||||
for key, value in data.items():
|
||||
setattr(self, key, value)
|
||||
return self
|
||||
|
||||
|
||||
class RelayDevice(Device):
|
||||
"""
|
||||
|
@ -48,22 +91,8 @@ class RelayDevice(Device):
|
|||
a relay. Each device only has two outputs, `OUT0` and `OUT2`.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.id = ""
|
||||
super().__init__()
|
||||
self.type = "RelayDevice"
|
||||
self.description = ""
|
||||
self.location = ""
|
||||
self.ip_address = ""
|
||||
self.locked = False
|
||||
|
||||
self.sub_devices = []
|
||||
self.sub_devices.append(RelayOutlet())
|
||||
self.sub_devices.append(RelayOutlet())
|
||||
self.sub_devices[0].id = 'OUT0'
|
||||
self.sub_devices[0].gpio = '0'
|
||||
self.sub_devices[1].id = 'OUT2'
|
||||
self.sub_devices[1].gpio = '2'
|
||||
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
"""
|
||||
|
@ -97,24 +126,8 @@ class RelayDevice(Device):
|
|||
|
||||
return state
|
||||
|
||||
def from_dict(self, data):
|
||||
"""
|
||||
Initializes self with data from JSON dict.
|
||||
"""
|
||||
for key, value in data.items():
|
||||
setattr(self, key, value)
|
||||
self.sub_devices = []
|
||||
for sub_dev_dict in data.get('sub_devices'):
|
||||
if sub_dev_dict.get('type') == 'RelayOutlet':
|
||||
sub_dev = RelayOutlet().from_dict(sub_dev_dict)
|
||||
self.sub_devices.append(sub_dev)
|
||||
else:
|
||||
typ = sub_dev.get('type')
|
||||
raise ValueError(f"Unknown sub_device type {typ}")
|
||||
return self
|
||||
|
||||
|
||||
class RelayOutlet:
|
||||
class RelayOutlet(SubDevice):
|
||||
"""
|
||||
Represents a single outlet on a RelayDevice.
|
||||
"""
|
||||
|
@ -125,42 +138,24 @@ class RelayOutlet:
|
|||
self.gpio = ""
|
||||
self.state = False
|
||||
|
||||
def from_dict(self, data):
|
||||
"""
|
||||
Initializes self with data from JSON dict.
|
||||
"""
|
||||
for key, value in data.items():
|
||||
setattr(self, key, value)
|
||||
return self
|
||||
|
||||
|
||||
class LightStrip(Device):
|
||||
"""
|
||||
Represents an RGB LED light strip controller.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.id = ""
|
||||
super().__init__()
|
||||
self.type = "LightStrip"
|
||||
self.description = ""
|
||||
self.location = ""
|
||||
self.ip_address = ""
|
||||
self.locked = False
|
||||
|
||||
def from_dict(self, data):
|
||||
"""
|
||||
Initializes self with data from JSON dict.
|
||||
"""
|
||||
for key, value in data.items():
|
||||
setattr(self, key, value)
|
||||
self.sub_devices = []
|
||||
for sub_dev_dict in data.get('sub_devices'):
|
||||
if sub_dev_dict.get('type') == 'RelayOutlet':
|
||||
sub_dev = RelayOutlet().from_dict(sub_dev_dict)
|
||||
self.sub_devices.append(sub_dev)
|
||||
else:
|
||||
typ = sub_dev.get('type')
|
||||
raise ValueError(f"Unknown sub_device type {typ}")
|
||||
return self
|
||||
|
||||
class NeoPixel(SubDevice):
|
||||
"""
|
||||
Represents a single NeoPixel in a LightStrip.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.id = ""
|
||||
self.type = "NeoPixel"
|
||||
self.color = [0,0,0] # JSON doesn't have tuples
|
||||
|
||||
|
||||
class DeviceEncoder(json.JSONEncoder):
|
||||
|
|
|
@ -109,18 +109,18 @@ nav span:hover {
|
|||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.led {
|
||||
.NeoPixel {
|
||||
padding: 0.25em;
|
||||
margin: 0.125em;
|
||||
}
|
||||
|
||||
.led_color {
|
||||
.NeoPixel_color {
|
||||
border-radius: 0.25em;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.led_color_input {
|
||||
.NeoPixel_color_input {
|
||||
opacity: 0;
|
||||
display: block;
|
||||
width: 1em;
|
||||
|
|
|
@ -3,6 +3,7 @@ var socket;
|
|||
function load() {
|
||||
socket = init_websocket();
|
||||
|
||||
// initialize RelayOutlet SVG color
|
||||
Object.entries(init_state).forEach(([device_id, sub_devs]) => {
|
||||
let device = document.querySelector('#' + device_id);
|
||||
Object.entries(sub_devs).forEach(([sub_device_id, state]) => {
|
||||
|
@ -60,11 +61,12 @@ function onmessage (e) {
|
|||
socket.events[event](data);
|
||||
}
|
||||
|
||||
function onclose(e) {
|
||||
async function onclose(e) {
|
||||
if (e.wasClean) { return; } // no need to reconnect
|
||||
console.log(e);
|
||||
console.log('Websocket lost connection to server. Re-trying...');
|
||||
socket = init_websocket();
|
||||
await sleep(5000);
|
||||
}
|
||||
|
||||
function onerror(e) {
|
||||
|
@ -247,3 +249,7 @@ function get_object_from_svg(svg) {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="/static/juice.css">
|
||||
<script>
|
||||
const init_state = {{ init_state|tojson|safe }};
|
||||
const ws_uri = "{{ request.app.router['ws'].url_for() }}";
|
||||
const ws_uri = "{{ url('ws') }}";
|
||||
</script>
|
||||
<script type="text/javascript" src="/static/juice.js"></script>
|
||||
<script>window.onload = load;</script>
|
||||
|
@ -37,23 +37,19 @@
|
|||
<div class="location editable"><span class="field_value">{{ device.location }}</span>{% if not device.locked %}<span class="edit font-awesome" onclick="edit_field(this.parentElement)"></span>{% endif %}</div>
|
||||
<div class="ip_address editable"><span class="field_value">{{ device.ip_address }}</span>{% if not device.locked %}<span class="edit font-awesome" onclick="edit_field(this.parentElement)"></span>{% endif %}</div>
|
||||
<div class="sub_devices">
|
||||
{% if device.type == 'RelayDevice' %}
|
||||
{% for sub_device in device.sub_devices %}
|
||||
{% for sub_device in device.sub_devices %}
|
||||
<div class="sub_device {{ sub_device.type }} {{ sub_device.id }}">
|
||||
{% if device.type == 'RelayDevice' %}
|
||||
<div class="id">{{ sub_device.id }}</div>
|
||||
<object class="outlet_image" aria-label="Outlet Image" data="/static/outlet.svg"></object>
|
||||
<div class="description editable"><span class="field_value">{{ sub_device.description }}</span>{% if not device.locked %}<span class="edit font-awesome" onclick="edit_field(this.parentElement)"></span>{% endif %}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% elif device.type == 'LightStrip' %}
|
||||
{% for n in range(24) %}
|
||||
<div class="sub_device led led{{n}}">
|
||||
<label class="led_color">
|
||||
<input class="led_color_input" type="color">
|
||||
{% elif device.type == 'LightStrip' %}
|
||||
<label class="NeoPixel_color" style="background-color: {{ sub_device.color|html_color }}">
|
||||
<input class="NeoPixel_color_input" type="color" value="{{ sub_device.color|html_color }}">
|
||||
</label>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
|
Loading…
Reference in New Issue
Block a user