Adds basic functionality to web interface; partial function of LCD driver
This commit is contained in:
parent
38cee3f4b0
commit
fef826f1d3
|
@ -9,6 +9,7 @@ setup (name = 'trespassed',
|
|||
license = "APLv2",
|
||||
keywords = "",
|
||||
install_requires = ['twisted[tls]', 'sysfs-gpio','crcmod',
|
||||
'enum34', 'pyserial','attrs','pyopenssl','klein','jinja2'],
|
||||
'enum34', 'pyserial','attrs','pyopenssl',
|
||||
'klein','jinja2','smbus-cffi'],
|
||||
include_package_data = True,
|
||||
)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import sys
|
||||
|
||||
from twisted.internet import defer, reactor
|
||||
from twisted.python import log
|
||||
|
||||
|
@ -45,6 +47,10 @@ def set_output(pin_no, level):
|
|||
log.msg("Clearing {}".format(pin_no))
|
||||
pin.reset()
|
||||
|
||||
def get_output(pin_no):
|
||||
pin = PINS[pin_no]
|
||||
return pin.read()
|
||||
|
||||
skip = True
|
||||
def quit(*args, **kwargs):
|
||||
global skip
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
import time
|
||||
from smbus import SMBus
|
||||
|
||||
ADDR = 0x20
|
||||
BUS = 1
|
||||
|
||||
LCD_DATA = 1
|
||||
LCD_CMD = 0
|
||||
|
||||
LCD_LINE_ADDR = {0: 0x80,
|
||||
1: 0xc0}
|
||||
|
||||
# Timing constants
|
||||
E_PULSE = 0.0005
|
||||
E_DELAY = 0.0005
|
||||
|
||||
LCD_WIDTH = 16
|
||||
|
||||
# MCP23008 Registers
|
||||
IODIR = 0x00
|
||||
IOCON = 0x05
|
||||
IOCON_SREAD = (1 << 5)
|
||||
IOCON_DISSLW = (1 << 4)
|
||||
IOCON_ODR = (1 << 2)
|
||||
IOCON_INTPOL = (1 << 1)
|
||||
GPIO = 0x09
|
||||
|
||||
# HD44780 Pins
|
||||
RS = (1 << 1)
|
||||
ENABLE = (1 << 2)
|
||||
DB4 = (1 << 3)
|
||||
DB5 = (1 << 4)
|
||||
DB6 = (1 << 5)
|
||||
DB7 = (1 << 6)
|
||||
|
||||
LCD_BACKLIGHT = (1 << 7)
|
||||
|
||||
# HD44780 Commands
|
||||
|
||||
|
||||
class LCD(object):
|
||||
def __init__(self, addr=ADDR):
|
||||
self.addr = addr
|
||||
self.bus = SMBus(BUS)
|
||||
self._init_mcp()
|
||||
self._init_hd44780()
|
||||
|
||||
def _init_mcp(self):
|
||||
# Set MCP23008 pins as outputs
|
||||
self._write_reg(IODIR, 0x00)
|
||||
# Disable incrementing pointer
|
||||
self._write_reg(IOCON, IOCON_SREAD)
|
||||
# Enable Backlight
|
||||
self._write_reg(0x09, 1 << 7)
|
||||
|
||||
def _write4(self, bits):
|
||||
message = (bits << 3) | LCD_BACKLIGHT
|
||||
self.bus.write_byte(self.addr, message)
|
||||
self._latch(message)
|
||||
|
||||
def write_cmd(self, byte):
|
||||
self._write4((byte & 0xf0) >> 4)
|
||||
self._write4((byte & 0x0f))
|
||||
|
||||
def _init_hd44780(self):
|
||||
# Initialize, set to 4bit mode
|
||||
self._write4(DB5)
|
||||
self.write_cmd((DB5 << 4) | DB7)
|
||||
self.write_cmd(1) # Clear Display
|
||||
self.write_cmd(0 | (DB4 | DB5 | DB6 | DB7)) # Display ON, Cursor ON, Cursor Blinking
|
||||
self.write_cmd(0 | (DB5 | DB6)) # Entry Mode
|
||||
|
||||
def _write_reg(self, reg, val):
|
||||
self.bus.write_byte_data(self.addr, reg, val)
|
||||
|
||||
# def _write(self, byte, backlight=LCD_BACKLIGHT_ON, mode=0):
|
||||
# bits_high = (mode << 1) | ((byte & 0xF0) << 3) | backlight
|
||||
# bits_low = (mode << 1) | ((byte & 0xf) << 3) | backlight
|
||||
|
||||
# self.bus.write(self.addr, bits_high)
|
||||
# self._latch(bits_high)
|
||||
|
||||
# self.bus.write(self.addr, bits_low)
|
||||
# self._latch(bits_low)
|
||||
|
||||
def _latch(self, bits):
|
||||
time.sleep(E_DELAY)
|
||||
self.bus.write_byte(self.addr, bits | ENABLE)
|
||||
time.sleep(E_PULSE)
|
||||
self.bus.write_byte(self.addr, (bits & ~ENABLE))
|
||||
time.sleep(E_DELAY)
|
||||
|
||||
# def write(self, line, string):
|
||||
# string = string.ljust(LCD_WIDTH, " ")[:LCD_WIDTH]
|
||||
# self._write(line)
|
||||
# for i in range(LCD_WIDTH):
|
||||
# self.write_cmd(ord(string[i]) | RS)
|
||||
|
||||
LCD_SINGLETON = LCD()
|
||||
|
||||
def lcd_write_status(status):
|
||||
return
|
||||
lines = status.split('\n')[:2]
|
||||
for i in range(len(lines)):
|
||||
LCD_SINGLETON.write(LCD_LINE_ADDR[i], lines[i])
|
|
@ -13,7 +13,7 @@ from twisted.application.internet import TimerService
|
|||
from twisted.internet import protocol, reactor, defer
|
||||
from twisted.python import log
|
||||
|
||||
from trespassed.game import input_parse
|
||||
from trespassed.game import input_parse, INPUT_MAP
|
||||
from trespassed.gpio import set_output, OUTPUTS
|
||||
from trespassed.email import email_failure
|
||||
from trespassed.media import play_sound_effect
|
||||
|
|
|
@ -2,6 +2,7 @@ from twisted.application.internet import TimerService
|
|||
from twisted.internet import reactor
|
||||
|
||||
from trespassed.timer import get_timer
|
||||
from trespassed.lcd import lcd_write_status
|
||||
|
||||
__all__ = ['get_status', 'set_status',
|
||||
'status_service', 'get_log', 'clear_log']
|
||||
|
@ -12,12 +13,14 @@ class Status(object):
|
|||
def __init__(self, name, initial_status='Loading...'):
|
||||
self.name = name
|
||||
self.log = []
|
||||
self.update()
|
||||
self.set(initial_status)
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
self._status1 = "{:.10} {:5}".format(self.name,
|
||||
get_timer().get_human())
|
||||
lcd_write_status(self.get())
|
||||
|
||||
def set(self, status):
|
||||
self._status2 = status
|
||||
self.log.append({'when': get_timer().get_human(),
|
||||
|
|
|
@ -9,12 +9,17 @@ from twisted.python import log
|
|||
from twisted.web.server import Site
|
||||
from twisted.web.static import File
|
||||
|
||||
from trespassed.gpio import OUTPUTS, get_output, set_output
|
||||
from trespassed.status import get_status, get_log
|
||||
|
||||
app = Klein()
|
||||
env = jinja2.Environment(
|
||||
loader=jinja2.PackageLoader(__name__, 'web/templates'))
|
||||
|
||||
def output_status(number):
|
||||
return get_output(number)
|
||||
env.filters['output_status'] = output_status
|
||||
|
||||
@app.route('/static/', branch=True)
|
||||
def static(request):
|
||||
return File(resource_filename(__name__, 'web/static/'))
|
||||
|
@ -34,6 +39,17 @@ def status(request):
|
|||
'status2': status2,
|
||||
'log': get_log()})
|
||||
|
||||
@app.route('/outputs', methods=['GET', 'POST'])
|
||||
@defer.inlineCallbacks
|
||||
def outputs(request):
|
||||
if request.method == 'POST':
|
||||
args = json.loads(request.content.getvalue())
|
||||
yield set_output(*args)
|
||||
request.setResponseCode(200)
|
||||
defer.returnValue('{}')
|
||||
page = env.get_template('outputs.html')
|
||||
defer.returnValue(page.render(outputs=OUTPUTS))
|
||||
|
||||
class WebService(service.Service):
|
||||
def __init__(self, endpoint_desc):
|
||||
self.endpoint_desc = endpoint_desc
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
define(['ajax'], function(ajax) {
|
||||
'use strict';
|
||||
|
||||
function button_handler(evt) {
|
||||
if (evt.target.classList.contains('active')) {
|
||||
evt.stopPropagation();
|
||||
return;
|
||||
}
|
||||
console.log(evt);
|
||||
var parts = evt.target.id.split('-');
|
||||
var output_id = parseInt(parts[parts.length - 1]);
|
||||
var to_state = parts[parts.length - 2] === 'on' ? true : false;
|
||||
var partner_id = 'btn-' + (to_state ? 'off-' : 'on-') + output_id;
|
||||
console.log(partner_id);
|
||||
ajax.post_json('/outputs', [output_id, to_state]).then(
|
||||
function () {
|
||||
evt.target.classList.add('active');
|
||||
var partner = document.getElementById(partner_id);
|
||||
partner.classList.remove('active');
|
||||
}, function () {
|
||||
alert("Failed to set output");
|
||||
});
|
||||
evt.stopPropagation();
|
||||
}
|
||||
|
||||
document.getElementById('output_table').addEventListener('click',
|
||||
button_handler);
|
||||
});
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
{% block sidebar %}
|
||||
<li class="active"><a href="/">Overview <span class="sr-only">(current)</span></a></li>
|
||||
<li><a href="/beacons">Output Control</a></li>
|
||||
<li><a href="/outputs">Output Control</a></li>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
{% extends "base.html" %}
|
||||
{% block title %} Override Outputs {% endblock %}
|
||||
|
||||
{% block head_js %}
|
||||
<script data-main="static/js/outputs"
|
||||
src="/static/js/require.min.js"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<li><a href="/">Overview <span class="sr-only">(current)</span></a></li>
|
||||
<li class="active"><a href="/outputs">Output Control</a></li>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- <h1 class="page-header">Dashboard</h1> -->
|
||||
<div class="row">
|
||||
<div id="table_div" class="col-sm-12 col-md-12">
|
||||
<!-- <h4 class="sub-header">Log</h3> -->
|
||||
<table class="table">
|
||||
<thead>
|
||||
<th>Output</th>
|
||||
<th>Actions</th>
|
||||
</thead>
|
||||
<tbody id="output_table">
|
||||
{% for output in outputs %}
|
||||
<tr><td>{{ output.name }}</td>
|
||||
<td>
|
||||
{% if output.value | output_status %}
|
||||
<button id="btn-on-{{ output.value }}" class="btn btn-primary btn-lg active">On</button>
|
||||
<button id="btn-off-{{ output.value }}" class="btn btn-primary btn-lg">Off</button>
|
||||
{% else %}
|
||||
<button id="btn-on-{{ output.value }}" class="btn btn-primary btn-lg">On</button>
|
||||
<button id="btn-off-{{ output.value }}" class="btn btn-primary btn-lg active">Off</button>
|
||||
{% endif %}
|
||||
</td>
|
||||
<tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue