From 7db1f9421548facea169db49d0e64a03c1ec84bd Mon Sep 17 00:00:00 2001 From: Thomas Ibbotson Date: Fri, 6 May 2016 19:19:56 +0000 Subject: [PATCH] First commit --- .gitignore | 2 + db.sqlite3 | Bin 0 -> 36864 bytes lazytwinkle/__init__.py | 0 lazytwinkle/settings.py | 122 +++++++++++++++++++++++++++ lazytwinkle/urls.py | 22 +++++ lazytwinkle/wsgi.py | 16 ++++ lib/__init__.py | 0 lib/remote_light/__init__.py | 1 + lib/remote_light/eventClient.py | 39 +++++++++ lib/remote_light/lightSwitch.py | 94 +++++++++++++++++++++ lib/remote_light/socketController.py | 67 +++++++++++++++ lights/__init__.py | 0 lights/admin.py | 3 + lights/apps.py | 7 ++ lights/migrations/__init__.py | 0 lights/models.py | 5 ++ lights/templates/lights/index.html | 10 +++ lights/tests.py | 3 + lights/urls.py | 10 +++ lights/views.py | 30 +++++++ manage.py | 10 +++ 21 files changed, 441 insertions(+) create mode 100644 .gitignore create mode 100644 db.sqlite3 create mode 100644 lazytwinkle/__init__.py create mode 100644 lazytwinkle/settings.py create mode 100644 lazytwinkle/urls.py create mode 100644 lazytwinkle/wsgi.py create mode 100644 lib/__init__.py create mode 100644 lib/remote_light/__init__.py create mode 100644 lib/remote_light/eventClient.py create mode 100644 lib/remote_light/lightSwitch.py create mode 100644 lib/remote_light/socketController.py create mode 100644 lights/__init__.py create mode 100644 lights/admin.py create mode 100644 lights/apps.py create mode 100644 lights/migrations/__init__.py create mode 100644 lights/models.py create mode 100644 lights/templates/lights/index.html create mode 100644 lights/tests.py create mode 100644 lights/urls.py create mode 100644 lights/views.py create mode 100755 manage.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c4819f3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.pyc +*.sw[op] diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..1164363b4a7a1c2390ffb414d3b7f9172be36e2a GIT binary patch literal 36864 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 literal 0 HcmV?d00001 diff --git a/lazytwinkle/__init__.py b/lazytwinkle/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lazytwinkle/settings.py b/lazytwinkle/settings.py new file mode 100644 index 0000000..2ccf089 --- /dev/null +++ b/lazytwinkle/settings.py @@ -0,0 +1,122 @@ +""" +Django settings for lazytwinkle project. + +Generated by 'django-admin startproject' using Django 1.9.6. + +For more information on this file, see +https://docs.djangoproject.com/en/1.9/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/1.9/ref/settings/ +""" + +import os + +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = '_=$7elaigl)4ded013_0rgm=dh1bo$txsn_bg%&mr)24fm-g%@' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'lights.apps.LightsConfig', + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +] + +MIDDLEWARE_CLASSES = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'lazytwinkle.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'lazytwinkle.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/1.9/ref/settings/#databases + +DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} + + +# Password validation +# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/1.9/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'GMT' + +USE_I18N = True + +USE_L10N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/1.9/howto/static-files/ + +STATIC_URL = '/static/' diff --git a/lazytwinkle/urls.py b/lazytwinkle/urls.py new file mode 100644 index 0000000..b53fb85 --- /dev/null +++ b/lazytwinkle/urls.py @@ -0,0 +1,22 @@ +"""lazytwinkle URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/1.9/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.conf.urls import url, include + 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) +""" +from django.conf.urls import include, url +from django.contrib import admin + +urlpatterns = [ + url(r'^lights/', include('lights.urls')), + url(r'^admin/', admin.site.urls), +] diff --git a/lazytwinkle/wsgi.py b/lazytwinkle/wsgi.py new file mode 100644 index 0000000..fdb8405 --- /dev/null +++ b/lazytwinkle/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for lazytwinkle project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lazytwinkle.settings") + +application = get_wsgi_application() diff --git a/lib/__init__.py b/lib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lib/remote_light/__init__.py b/lib/remote_light/__init__.py new file mode 100644 index 0000000..6bb3330 --- /dev/null +++ b/lib/remote_light/__init__.py @@ -0,0 +1 @@ +__author__ = 'ibbo' diff --git a/lib/remote_light/eventClient.py b/lib/remote_light/eventClient.py new file mode 100644 index 0000000..fea458c --- /dev/null +++ b/lib/remote_light/eventClient.py @@ -0,0 +1,39 @@ +import socket +import time +import socketController as sc + +class EventClient: + def __init__(self, host, port): + self.host = host + self.port = port + + def connect(self): + self.socket = socket.create_connection((self.host, self.port)) + + def defaultEventHandler(data): + print(repr(data)) + + def pollEvents(self, eventHandler=defaultEventHandler): + while True: + data = self.socket.recv(1024) + eventHandler(data) + time.sleep(1) + +def switchHandler(data): + if not data: + return + print("Received: %s" % data) + s = data.split(':') + switchId = int(s[0]) + switchState = s[1].strip() == 'true' + if switchState: + print("Switch %d is on" % switchId) + sc.turnOnSocket() + else: + print("Switch %d is off" % switchId) + sc.turnOffSocket() + +if __name__ == "__main__": + ec = EventClient("localhost", 18000) + ec.connect() + ec.pollEvents(switchHandler) diff --git a/lib/remote_light/lightSwitch.py b/lib/remote_light/lightSwitch.py new file mode 100644 index 0000000..c270874 --- /dev/null +++ b/lib/remote_light/lightSwitch.py @@ -0,0 +1,94 @@ +import RPi.GPIO as GPIO +import signal +import sys +import time + + +def setupGPIO(): + GPIO.setmode(GPIO.BOARD) + # K0-K3 data inputs + GPIO.setup(11, GPIO.OUT) + GPIO.setup(15, GPIO.OUT) + GPIO.setup(16, GPIO.OUT) + GPIO.setup(13, GPIO.OUT) + + # ASK/FSK + GPIO.setup(18, GPIO.OUT) + + # modulator + GPIO.setup(22, GPIO.OUT) + + # Disable modulator + GPIO.output(22, False) + + # Set modulator to ASK for On Off Keying + # by setting MODSEL pin lo + GPIO.output(18, False) + + # Init K0-K3 inputs of the encoder to 0000 + GPIO.output(11, False) + GPIO.output(15, False) + GPIO.output(16, False) + GPIO.output(13, False) + +def lightSwitchHandler(data): + if not data: + return + s = data.split(':') + switchId = int(s[0]) + switchState = s[1].strip() == 'true' + switchLight(switchState) + +def programPlug(): + switchLight(True) + switchLight(False) + switchAll(True) + switchAll(False) + +def switchLight(on): + # Last pin determines on or off + if on: + GPIO.output(11, True) + GPIO.output(15, True) + GPIO.output(16, True) + GPIO.output(13, True) + else: + GPIO.output(11, True) + GPIO.output(15, True) + GPIO.output(16, True) + GPIO.output(13, False) + + # Send the signal by pulsing the modulator + pulse_modulator() + +def switchAll(on): + if on: + GPIO.output(11, True) + GPIO.output(15, True) + GPIO.output(16, False) + GPIO.output(13, True) + else: + GPIO.output(11, True) + GPIO.output(15, True) + GPIO.output(16, False) + GPIO.output(13, False) + + pulse_modulator() + +def pulse_modulator(): + # let it settle, encoder requires this + time.sleep(0.1) + GPIO.output(22, True) + time.sleep(0.25) + GPIO.output(22, False) + +def signal_handler(signal, frame): + sys.exit(0) + +def cleanup(): + switchLight(False) + GPIO.cleanup() + +setupGPIO() +if __name__ == "__main__": + pass diff --git a/lib/remote_light/socketController.py b/lib/remote_light/socketController.py new file mode 100644 index 0000000..d623bd9 --- /dev/null +++ b/lib/remote_light/socketController.py @@ -0,0 +1,67 @@ +__author__ = 'ibbo' +#import the required modules +import RPi.GPIO as GPIO +import time + +# set the pins numbering mode +GPIO.setmode(GPIO.BOARD) + +# Select the GPIO pins used for the encoder K0-K3 data inputs +GPIO.setup(11, GPIO.OUT) +GPIO.setup(15, GPIO.OUT) +GPIO.setup(16, GPIO.OUT) +GPIO.setup(13, GPIO.OUT) + +# Select the signal to select ASK/FSK +GPIO.setup(18, GPIO.OUT) + +# Select the signal used to enable/disable the modulator +GPIO.setup(22, GPIO.OUT) + +# Disable the modulator by setting CE pin lo +GPIO.output (22, False) + +# Set the modulator to ASK for On Off Keying +# by setting MODSEL pin lo +GPIO.output (18, False) + +# Initialise K0-K3 inputs of the encoder to 0000 +GPIO.output (11, False) +GPIO.output (15, False) +GPIO.output (16, False) +GPIO.output (13, False) + +# The On/Off code pairs correspond to the hand controller codes. +# True = '1', False ='0' + +def turnOnSocket(): + # Set K0-K3 + print "sending code 1111 socket 1 on" + GPIO.output (11, True) + GPIO.output (15, True) + GPIO.output (16, True) + GPIO.output (13, True) + # let it settle, encoder requires this + time.sleep(0.1) + # Enable the modulator + GPIO.output (22, True) + # keep enabled for a period + time.sleep(0.25) + # Disable the modulator + GPIO.output (22, False) + +def turnOffSocket(): + # Set K0-K3 + print "sending code 0111 Socket 1 off" + GPIO.output (11, True) + GPIO.output (15, True) + GPIO.output (16, True) + GPIO.output (13, False) + # let it settle, encoder requires this + time.sleep(0.1) + # Enable the modulator + GPIO.output (22, True) + # keep enabled for a period + time.sleep(0.25) + # Disable the modulator + GPIO.output (22, False) diff --git a/lights/__init__.py b/lights/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lights/admin.py b/lights/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/lights/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/lights/apps.py b/lights/apps.py new file mode 100644 index 0000000..2edddae --- /dev/null +++ b/lights/apps.py @@ -0,0 +1,7 @@ +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class LightsConfig(AppConfig): + name = 'lights' diff --git a/lights/migrations/__init__.py b/lights/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lights/models.py b/lights/models.py new file mode 100644 index 0000000..bd4b2ab --- /dev/null +++ b/lights/models.py @@ -0,0 +1,5 @@ +from __future__ import unicode_literals + +from django.db import models + +# Create your models here. diff --git a/lights/templates/lights/index.html b/lights/templates/lights/index.html new file mode 100644 index 0000000..e0fb881 --- /dev/null +++ b/lights/templates/lights/index.html @@ -0,0 +1,10 @@ +

Use the buttons below to switch the conservatory lights on/off

+ +
+{% csrf_token %} + +
+
+{% csrf_token %} + +
diff --git a/lights/tests.py b/lights/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/lights/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/lights/urls.py b/lights/urls.py new file mode 100644 index 0000000..1ac9976 --- /dev/null +++ b/lights/urls.py @@ -0,0 +1,10 @@ +from django.conf.urls import include, url +from django.contrib import admin + +from . import views + +urlpatterns = [ + url(r'^$', views.index, name='index'), + url(r'^on$', views.on, name='on'), + url(r'^off$', views.off, name='off'), +] diff --git a/lights/views.py b/lights/views.py new file mode 100644 index 0000000..a3510b0 --- /dev/null +++ b/lights/views.py @@ -0,0 +1,30 @@ +from django.shortcuts import render +from django.template import loader +from django.http import HttpResponse, HttpResponseRedirect +from django.core.urlresolvers import reverse + +import zmq + +# Create your views here. +def index(request): + template = loader.get_template('lights/index.html'); + context = {} + return render(request, 'lights/index.html', context) + +def on(request): + port = "5556" + context = zmq.Context() + socket = context.socket(zmq.PAIR) + socket.connect("tcp://localhost:%s" % port) + socket.send("1: true") + socket.close() + return HttpResponseRedirect('/lights') + +def off(request): + port = "5556" + context = zmq.Context() + socket = context.socket(zmq.PAIR) + socket.connect("tcp://localhost:%s" % port) + socket.send("1: false") + socket.close() + return HttpResponseRedirect('/lights') diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..729f86c --- /dev/null +++ b/manage.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lazytwinkle.settings") + + from django.core.management import execute_from_command_line + + execute_from_command_line(sys.argv)