first commit
This commit is contained in:
commit
0399f9076a
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
__pycache__/
|
||||
*.swp
|
||||
*.swo
|
||||
devices.json
|
13
README.md
Normal file
13
README.md
Normal file
|
@ -0,0 +1,13 @@
|
|||
# Juice
|
||||
A hub for controlling IOT devices.
|
||||
|
||||
## Requirements
|
||||
Python 3.6+
|
||||
Python packages: `flask gunicorn requests`
|
||||
|
||||
## Install
|
||||
1. Get on the floor
|
||||
2. Walk the dinosaur
|
||||
|
||||
## Usage
|
||||
`gunicorn -b localhost:5300 -e SCRIPT_NAME=/juice juice:app`
|
107
juice.py
Normal file
107
juice.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
#!/usr/bin/env python3
|
||||
"""
|
||||
A hub for controlling IOT devices.
|
||||
"""
|
||||
import re
|
||||
import json
|
||||
|
||||
import requests
|
||||
from flask import Flask, render_template
|
||||
|
||||
|
||||
class RelayDevice:
|
||||
"""
|
||||
Represents a relay receptacle device controlled by an ESP-01. The
|
||||
ESP-01 acts a simple switch to turn each receptable on or off via
|
||||
a relay. Each device only has two outputs, `OUT0` and `OUT2`.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.id = ""
|
||||
self.description = ""
|
||||
self.location = ""
|
||||
self.ip_address = ""
|
||||
self.sub_devices = {}
|
||||
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
"""
|
||||
Queries the physical device and updates the internal model as
|
||||
appropriate.
|
||||
"""
|
||||
for name, device in self.sub_devices.items():
|
||||
res = requests.get(self.ip_address)
|
||||
gpio0 = re.search(r"GPIO0: (\bLow|\bHigh)", res.text).groups()[0]
|
||||
device.state = gpio0 == 'High'
|
||||
|
||||
def from_dict(self, data):
|
||||
"""
|
||||
Initializes self with data from JSON dict.
|
||||
"""
|
||||
self.id = data['id']
|
||||
self.description = data['description']
|
||||
self.location = data['location']
|
||||
self.ip_address = data['ip_address']
|
||||
self.sub_devices = {}
|
||||
for sub_dev_type, sub_devs in data['sub_devices'].items():
|
||||
if sub_dev_type == 'RelayOutlet':
|
||||
self.sub_devices[sub_dev_type] = []
|
||||
for sub_dev in sub_devs:
|
||||
sub_dev = RelayOutlet().from_dict(sub_dev)
|
||||
self.sub_devices[sub_dev_type].append(sub_dev)
|
||||
else:
|
||||
raise ValueError(f"Unknown sub_device type {dev_name}")
|
||||
return self
|
||||
|
||||
|
||||
class RelayOutlet:
|
||||
"""
|
||||
Represents a single outlet on a RelayDevice.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.id = ""
|
||||
self.description = ""
|
||||
self.state = False
|
||||
|
||||
def from_dict(self, data):
|
||||
"""
|
||||
Initializes self with data from JSON dict.
|
||||
"""
|
||||
self.id = data['id']
|
||||
self.description = data['description']
|
||||
self.state = data['state']
|
||||
return self
|
||||
|
||||
|
||||
def init_network():
|
||||
"""
|
||||
Initializes the network of IOT devices.
|
||||
"""
|
||||
with open("devices.json", 'r') as file:
|
||||
data = file.read()
|
||||
data = json.loads(data)
|
||||
network = {}
|
||||
for dev_type, devices in data.items():
|
||||
if dev_type == 'RelayDevice':
|
||||
network[dev_type] = []
|
||||
for device in devices:
|
||||
device = RelayDevice().from_dict(device)
|
||||
network[dev_type].append(device)
|
||||
else:
|
||||
raise ValueError(f"Unknown device type {dev_name}")
|
||||
return network
|
||||
|
||||
|
||||
app = Flask(__name__)
|
||||
network = init_network()
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
"""
|
||||
The index page.
|
||||
"""
|
||||
return render_template('index.html', network=network)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5300)
|
0
static/juice.css
Normal file
0
static/juice.css
Normal file
0
static/juice.js
Normal file
0
static/juice.js
Normal file
31
templates/index.html
Normal file
31
templates/index.html
Normal file
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Juice</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/juice.css">
|
||||
<script type="text/javascript" src="/static/juice.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
{% for dev_type, devices in network.items() %}
|
||||
{% for device in devices %}
|
||||
<div class="{{ dev_type }}" id="{{ device.id }}">
|
||||
<div class="id">{{ device.id }}</div>
|
||||
<div class="description">{{ device.description }}</div>
|
||||
<div class="location">{{ device.location }}</div>
|
||||
<div class="ip_address">{{ device.ip_address }}</div>
|
||||
<div class="sub_devices">
|
||||
{% for sub_dev_type, sub_devs in device.sub_devices.items() %}
|
||||
{% for sub_dev in sub_devs %}
|
||||
<div class="{{ sub_dev_type }}" id="{{ sub_dev.id }}">
|
||||
<div class="id">{{ sub_dev.id }}</div>
|
||||
<div class="outlet_image">OUTLET_IMAGE</div>
|
||||
<div class="description">{{ sub_dev.description }}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user