This repository has been archived by the owner on Jul 15, 2020. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit aaf51b8
Showing
51 changed files
with
503 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
PINS=1234,5678 | ||
MQTT_HOST=192.168.1.123 | ||
MQTT_USER=username | ||
MQTT_PASS=correcthorsebatterystaple |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# dotenv | ||
.env | ||
|
||
# virtualenv | ||
.venv | ||
venv/ | ||
ENV/ | ||
|
||
# IDE | ||
.idea/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2017 Colin O'Dell <colinodell@gmail.com> | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# mqtt-control-panel | ||
|
||
A simple alarm control panel for Home Assistant's `manual_mqtt` alarm. Designed to run on a Raspberry Pi using an Adafruit 3.5" PiTFT. | ||
|
||
![](screenshot.png) | ||
|
||
# Hardware | ||
|
||
- Raspberry Pi Zero Wireless (other modern Pis will likely work fine) | ||
- Adafruit PiTFT 3.5" display | ||
|
||
# Requirements | ||
|
||
This project requires Python 2.7 with the following packages: | ||
|
||
- paho-mqtt | ||
- pygame | ||
- python-dotenv | ||
|
||
# Configuration | ||
|
||
Copy `.env.dist` to `.env` and update the values accordingly. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from ui import UI | ||
from button import Button | ||
from status import StatusLine |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Button is a simple tappable screen region. Each has: | ||
# - bounding rect ((X,Y,W,H) in pixels) | ||
# - a state | ||
# - image bitmap | ||
# - optional single callback function | ||
# - optional single value passed to callback | ||
|
||
# Default state for all buttons | ||
STATE_DEFAULT = 0 | ||
# State when the button is currently pressed | ||
STATE_PRESSED = 1 | ||
# Action buttons: action is available (proper pin has been entered) | ||
STATE_AVAILABLE = 2 | ||
# Action buttons: used to indicate which state the alarm is in | ||
STATE_ACTIVE = 3 | ||
# The following states are for the pin input indicator | ||
STATE_1 = 4 | ||
STATE_2 = 5 | ||
STATE_3 = 6 | ||
STATE_4_GOOD = 7 | ||
STATE_4_BAD = 8 | ||
|
||
|
||
class Button(object): | ||
def __init__(self, ui, rect, **kwargs): | ||
self.ui = ui | ||
self.rect = rect # Bounds | ||
self.imageFiles = {} | ||
self.bitmaps = {} # Lazy-loaded | ||
self.callback = None # Callback function | ||
self.value = None # Value passed to callback | ||
self.state = 0 | ||
for key, value in kwargs.iteritems(): | ||
if key == 'imageFiles': | ||
self.imageFiles = value | ||
elif key == 'cb': | ||
self.callback = value | ||
elif key == 'value': | ||
self.value = value | ||
|
||
def set_state(self, state): | ||
if state != self.state: | ||
self.state = state | ||
self.draw() | ||
|
||
def down(self, pos): | ||
if self.selected(pos): | ||
if self.state == STATE_DEFAULT and self.bitmaps.has_key(STATE_PRESSED): | ||
self.set_state(STATE_PRESSED) | ||
|
||
if self.callback: | ||
if self.value is None: | ||
self.callback() | ||
else: | ||
self.callback(self.value) | ||
|
||
return True | ||
|
||
def up(self, pos): | ||
if self.selected(pos) and self.state == STATE_PRESSED: | ||
self.set_state(STATE_DEFAULT) | ||
return True | ||
|
||
def selected(self, pos): | ||
x1 = self.rect[0] | ||
y1 = self.rect[1] | ||
x2 = x1 + self.rect[2] - 1 | ||
y2 = y1 + self.rect[3] - 1 | ||
if ((pos[0] >= x1) and (pos[0] <= x2) and | ||
(pos[1] >= y1) and (pos[1] <= y2)): | ||
return True | ||
return False | ||
|
||
def draw(self): | ||
if self.bitmaps: | ||
bitmap = self.bitmaps[self.state] if self.state in self.bitmaps else self.bitmaps[0] | ||
self.ui.blit(bitmap, | ||
(self.rect[0] + (self.rect[2] - bitmap.get_width()) / 2, | ||
self.rect[1] + (self.rect[3] - bitmap.get_height()) / 2)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import pygame | ||
|
||
class Image: | ||
def __init__(self, path, name): | ||
self.name = name | ||
try: | ||
self.bitmap = pygame.image.load(path + '/' + name + '.png') | ||
except: | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
class StatusLine: | ||
def __init__(self, ui, rect, color): | ||
self.ui = ui | ||
self.rect = rect | ||
self.color = color | ||
self.message = '' | ||
|
||
def set(self, message): | ||
if self.message != message: | ||
self.message = message | ||
|
||
# Draw the label | ||
self.ui.draw_text(self.message, self.rect, self.color) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import os | ||
|
||
import pygame | ||
|
||
from alarmpanel.button import STATE_DEFAULT | ||
|
||
# A simple UI which only redraws parts of the screen as needed (faster than redrawing the whole screen all the time) | ||
class UI: | ||
def __init__(self, background = None): | ||
# Init framebuffer/touchscreen environment variables | ||
os.putenv('SDL_VIDEODRIVER', 'fbcon') | ||
os.putenv('SDL_FBDEV', '/dev/fb1') | ||
os.putenv('SDL_MOUSEDRV', 'TSLIB') | ||
os.putenv('SDL_MOUSEDEV', '/dev/input/touchscreen') | ||
|
||
# Init pygame and screen | ||
print "Initting..." | ||
pygame.init() | ||
print "Setting Mouse invisible..." | ||
pygame.mouse.set_visible(False) | ||
print "Setting fullscreen..." | ||
modes = pygame.display.list_modes(16) | ||
self._screen = pygame.display.set_mode(modes[0], pygame.FULLSCREEN, 16) | ||
self._needs_update = True | ||
|
||
# Load background | ||
self._background = pygame.image.load(background) | ||
self._screen.fill(0) | ||
self._screen.blit(self._background, (0, 0)) | ||
pygame.display.update() | ||
|
||
# Load font | ||
self._font = pygame.font.SysFont("Arial", 24) | ||
|
||
self._images = [] | ||
self._buttons = [] | ||
|
||
self.update() | ||
|
||
def blit(self, *args, **kwargs): | ||
self._screen.blit(*args, **kwargs) | ||
self.schedule_update() | ||
|
||
def blit_background(self, rect): | ||
self._screen.blit(self._background, rect, rect) | ||
self.schedule_update() | ||
|
||
def load_images(self, path): | ||
import fnmatch | ||
from alarmpanel.image import Image | ||
|
||
for file in os.listdir(path): | ||
if fnmatch.fnmatch(file, '*.png'): | ||
name = file.split('.')[0] | ||
self._images.append(Image(path, name)) | ||
|
||
def create_button(self, rect, **kwargs): | ||
from alarmpanel import Button | ||
|
||
button = Button(self, rect, **kwargs) | ||
|
||
for buttonState, imageFile in button.imageFiles.iteritems(): # For each image name defined on the button... | ||
for image in self._images: # For each icon... | ||
if imageFile == image.name: # Compare names; match? | ||
button.bitmaps[buttonState] = image.bitmap # Assign Icon to Button | ||
button.imageFiles[buttonState] = None # Name no longer used; allow garbage collection | ||
|
||
button.draw() | ||
|
||
self._buttons.append(button) | ||
|
||
return button | ||
|
||
def create_status_line(self, rect, color=(255, 255, 255)): | ||
from alarmpanel import StatusLine | ||
return StatusLine(self, pygame.Rect(rect), color) | ||
|
||
def draw_text(self, message, rect, color): | ||
|
||
# Redraw the background area behind the text | ||
self.blit_background(rect) | ||
|
||
# Draw the label | ||
label = self._font.render(message, 1, color) | ||
self._screen.blit(label, rect) | ||
|
||
self.schedule_update() | ||
|
||
def schedule_update(self): | ||
self._needs_update = True | ||
|
||
def update(self): | ||
if self._needs_update: | ||
self._needs_update = False | ||
pygame.display.update() | ||
|
||
def process_input(self): | ||
# Process touchscreen input | ||
from alarmpanel.button import STATE_PRESSED | ||
for event in pygame.event.get(): | ||
if event.type is pygame.MOUSEBUTTONDOWN: | ||
pos = pygame.mouse.get_pos() | ||
for b in self._buttons: | ||
if b.down(pos): break | ||
elif event.type is pygame.MOUSEBUTTONUP: | ||
pos = pygame.mouse.get_pos() | ||
for b in self._buttons: | ||
if b.up(pos): pass | ||
# Redraw other buttons which might be stuck in the down position | ||
elif b.state == STATE_PRESSED: | ||
b.set_state(STATE_DEFAULT) |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.