initial push
This commit is contained in:
10
echo-master/Dockerfile
Normal file
10
echo-master/Dockerfile
Normal file
@@ -0,0 +1,10 @@
|
||||
FROM python:3.7
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY requirements.txt ./
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD [ "python", "./echo.py" ]
|
BIN
echo-master/__pycache__/echo.cpython-37.pyc
Normal file
BIN
echo-master/__pycache__/echo.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/__pycache__/echo.cpython-38.pyc
Normal file
BIN
echo-master/__pycache__/echo.cpython-38.pyc
Normal file
Binary file not shown.
9
echo-master/docker-compose.yml
Normal file
9
echo-master/docker-compose.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
version: '3.4'
|
||||
|
||||
services:
|
||||
echo:
|
||||
build: .
|
||||
volumes:
|
||||
- .:/usr/src/app
|
||||
ports:
|
||||
- 1337:1337
|
19
echo-master/echo.py
Normal file
19
echo-master/echo.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from echo_api.api import EchoAPI
|
||||
from echo_serial.serial_controller import EchoSerial
|
||||
from echo_scheduler.scheduler import EchoScheduler
|
||||
|
||||
import logging
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Start Echo Serial Handler
|
||||
EchoSerial.init()
|
||||
|
||||
# Start Echo Scheduler
|
||||
EchoScheduler.init()
|
||||
|
||||
# Start Echo API
|
||||
EchoAPI.init()
|
||||
|
||||
|
||||
|
||||
|
1
echo-master/echo_api/__init__.py
Normal file
1
echo-master/echo_api/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
BIN
echo-master/echo_api/__init__.pyc
Normal file
BIN
echo-master/echo_api/__init__.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_api/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
echo-master/echo_api/__pycache__/__init__.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_api/__pycache__/__init__.cpython-38.pyc
Normal file
BIN
echo-master/echo_api/__pycache__/__init__.cpython-38.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_api/__pycache__/api.cpython-37.pyc
Normal file
BIN
echo-master/echo_api/__pycache__/api.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_api/__pycache__/api.cpython-38.pyc
Normal file
BIN
echo-master/echo_api/__pycache__/api.cpython-38.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_api/__pycache__/auth.cpython-37.pyc
Normal file
BIN
echo-master/echo_api/__pycache__/auth.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_api/__pycache__/auth.cpython-38.pyc
Normal file
BIN
echo-master/echo_api/__pycache__/auth.cpython-38.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_api/__pycache__/device.cpython-37.pyc
Normal file
BIN
echo-master/echo_api/__pycache__/device.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_api/__pycache__/device.cpython-38.pyc
Normal file
BIN
echo-master/echo_api/__pycache__/device.cpython-38.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_api/__pycache__/devices.cpython-37.pyc
Normal file
BIN
echo-master/echo_api/__pycache__/devices.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_api/__pycache__/devices.cpython-38.pyc
Normal file
BIN
echo-master/echo_api/__pycache__/devices.cpython-38.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_api/__pycache__/devices_endpoint.cpython-37.pyc
Normal file
BIN
echo-master/echo_api/__pycache__/devices_endpoint.cpython-37.pyc
Normal file
Binary file not shown.
43
echo-master/echo_api/api.py
Normal file
43
echo-master/echo_api/api.py
Normal file
@@ -0,0 +1,43 @@
|
||||
import flask
|
||||
|
||||
from flask import request, abort, Flask, g
|
||||
from flask_restful import Resource, Api
|
||||
from flask_cors import CORS, cross_origin
|
||||
|
||||
import echo_api.auth as Auth
|
||||
|
||||
# Endpoints
|
||||
import echo_api.devices as DevicesAPI
|
||||
import echo_api.device as DeviceInfoAPI
|
||||
import echo_api.device as DeviceControlAPI
|
||||
|
||||
class EchoAPI:
|
||||
|
||||
# Initialize Flask API Object
|
||||
app = flask.Flask(__name__)
|
||||
cors = CORS(app)
|
||||
app.config['CORS_HEADERS'] = 'Content-Type'
|
||||
api = Api(app)
|
||||
|
||||
# Start API
|
||||
@staticmethod
|
||||
def init():
|
||||
EchoAPI.app.run(host='0.0.0.0', port=1337, debug=False)
|
||||
|
||||
@staticmethod
|
||||
@app.route('/')
|
||||
def index():
|
||||
if not Auth.Auth.verify(request):
|
||||
return {'status': 'failed', 'message': 'Not Authenticated!'}, 401
|
||||
|
||||
return {'status': 'success', 'message': 'Echo API is healthy and running!'}, 200
|
||||
|
||||
@staticmethod
|
||||
@app.errorhandler(404)
|
||||
def not_found(error):
|
||||
return {'status': 'failed', 'message': 'Endpoint not found!'}, 404
|
||||
|
||||
api.add_resource(DevicesAPI.DevicesAPI, '/devices')
|
||||
api.add_resource(DeviceInfoAPI.DeviceInfoAPI, '/device/<string:uuid>')
|
||||
api.add_resource(DeviceControlAPI.DeviceControlAPI, '/device')
|
||||
|
BIN
echo-master/echo_api/api.pyc
Normal file
BIN
echo-master/echo_api/api.pyc
Normal file
Binary file not shown.
14
echo-master/echo_api/auth.py
Normal file
14
echo-master/echo_api/auth.py
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
class Auth:
|
||||
|
||||
tokens = {
|
||||
'Bearer f8c85565-ece7-471e-999f-9bb6a7b61a4c': 'Nick Leeman Development'
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def verify(req):
|
||||
token = req.headers.get('Authorization')
|
||||
if token in Auth.tokens:
|
||||
return True
|
||||
else:
|
||||
return False
|
56
echo-master/echo_api/device.py
Normal file
56
echo-master/echo_api/device.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from flask_restful import Resource, Api, reqparse
|
||||
from flask import request
|
||||
from bson import json_util, ObjectId
|
||||
import json
|
||||
|
||||
import echo_db.database as EchoDB
|
||||
import echo_api.auth as Auth
|
||||
import echo_controller.controller as Controller
|
||||
|
||||
class DeviceInfoAPI(Resource):
|
||||
|
||||
def get(self, uuid):
|
||||
# Verify Auth
|
||||
if not Auth.Auth.verify(request):
|
||||
return {'status': 'failed', 'message': 'Not Authenticated!'}, 401
|
||||
|
||||
# Get Device
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
device = collection.find_one({"uuid": uuid})
|
||||
|
||||
# Check if Device Exists
|
||||
if device == None:
|
||||
return {'status': 'failed', 'message': 'Device not found!', 'data': {}}, 404
|
||||
|
||||
# Format and respond
|
||||
device_json = json.loads(json_util.dumps(device))
|
||||
return {'status': 'success', 'data': device_json}, 200
|
||||
|
||||
class DeviceControlAPI(Resource):
|
||||
def post(self):
|
||||
if not Auth.Auth.verify(request):
|
||||
return {'status': 'failed', 'message': 'Not Authenticated!'}, 401
|
||||
|
||||
parser = reqparse.RequestParser()
|
||||
parser.add_argument('uuid', required = True)
|
||||
parser.add_argument('action', required = True)
|
||||
parser.add_argument('data', required = False, default = {})
|
||||
|
||||
# Parse the arguments into an object
|
||||
args = parser.parse_args()
|
||||
|
||||
# Get Device
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
device = collection.find_one({'uuid': args['uuid']})
|
||||
|
||||
# Check if Device Exists
|
||||
if device == None:
|
||||
return {'status': 'failed', 'message': 'Device not found!'}, 200
|
||||
|
||||
if args['action'] not in device['actions']:
|
||||
return {'status': 'failed', 'message': 'Action not found!'}, 200
|
||||
|
||||
# Send Action to Echo Controller
|
||||
return Controller.Controller.handle_action(device, args['action'], args['data'])
|
||||
|
||||
|
18
echo-master/echo_api/devices.py
Normal file
18
echo-master/echo_api/devices.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from flask_restful import Resource, Api, reqparse
|
||||
from flask import request
|
||||
from bson import json_util, ObjectId
|
||||
import json
|
||||
|
||||
import echo_db.database as EchoDB
|
||||
import echo_api.auth as Auth
|
||||
|
||||
class DevicesAPI(Resource):
|
||||
|
||||
def get(self):
|
||||
if not Auth.Auth.verify(request):
|
||||
return {'status': 'failed', 'message': 'Not Authenticated!'}, 401
|
||||
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
devices = collection.find({})
|
||||
devices_json = json.loads(json_util.dumps(devices))
|
||||
return {'status': 'success', 'data': devices_json}, 200
|
0
echo-master/echo_controller/__init__.py
Normal file
0
echo-master/echo_controller/__init__.py
Normal file
BIN
echo-master/echo_controller/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
echo-master/echo_controller/__pycache__/__init__.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_controller/__pycache__/__init__.cpython-38.pyc
Normal file
BIN
echo-master/echo_controller/__pycache__/__init__.cpython-38.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
echo-master/echo_controller/__pycache__/blinds.cpython-37.pyc
Normal file
BIN
echo-master/echo_controller/__pycache__/blinds.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_controller/__pycache__/blinds.cpython-38.pyc
Normal file
BIN
echo-master/echo_controller/__pycache__/blinds.cpython-38.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
echo-master/echo_controller/__pycache__/led_strip.cpython-38.pyc
Normal file
BIN
echo-master/echo_controller/__pycache__/led_strip.cpython-38.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_controller/__pycache__/sensor.cpython-37.pyc
Normal file
BIN
echo-master/echo_controller/__pycache__/sensor.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_controller/__pycache__/sensor.cpython-38.pyc
Normal file
BIN
echo-master/echo_controller/__pycache__/sensor.cpython-38.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_controller/__pycache__/switch.cpython-37.pyc
Normal file
BIN
echo-master/echo_controller/__pycache__/switch.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_controller/__pycache__/switch.cpython-38.pyc
Normal file
BIN
echo-master/echo_controller/__pycache__/switch.cpython-38.pyc
Normal file
Binary file not shown.
177
echo-master/echo_controller/air_conditioner.py
Normal file
177
echo-master/echo_controller/air_conditioner.py
Normal file
@@ -0,0 +1,177 @@
|
||||
import datetime
|
||||
import time
|
||||
import sys
|
||||
import echo_serial.serial_controller as EchoSerial
|
||||
import echo_db.database as EchoDB
|
||||
import _thread
|
||||
|
||||
class AirConditioner:
|
||||
|
||||
@staticmethod
|
||||
def handle_action(device, action, data):
|
||||
actionData = device['actions'][action]
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
|
||||
# Check if a thread is using the blinds, if so return.
|
||||
if device['status'] == "busy":
|
||||
return {'status': 'failed', 'message': 'Air Conditioner is being controlled by Echo, Please wait till finished.'}, 200
|
||||
|
||||
if action == "on":
|
||||
|
||||
if device['status'] == "on":
|
||||
return {'status': 'failed', 'message': 'Air conditioning is already on!'}, 200
|
||||
|
||||
# Update Database
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'on' }})
|
||||
|
||||
EchoSerial.EchoSerial.send_commmand(device, "power")
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
if action == "off":
|
||||
|
||||
if device['status'] == "off":
|
||||
return {'status': 'failed', 'message': 'Air conditioning is already off!'}, 200
|
||||
|
||||
EchoSerial.EchoSerial.send_commmand(device, "power")
|
||||
|
||||
# Update Database
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'off' }})
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
if action == "set_fan_speed":
|
||||
selected_speed = data
|
||||
|
||||
if selected_speed == {}:
|
||||
return {'status': 'failed', 'message': 'Please select a speed!'}, 200
|
||||
|
||||
if selected_speed == device['fan_speed']:
|
||||
return {'status': 'failed', 'message': 'Fan speed already set to requested speed!'}, 200
|
||||
|
||||
if device['status'] == "off":
|
||||
return {'status': 'failed', 'message': 'Air Conditioner must be on to change fan speeds!'}, 200
|
||||
|
||||
EchoSerial.EchoSerial.send_commmand(device, "fanspeed")
|
||||
|
||||
if device['fan_speed'] == "low":
|
||||
# We just put the speed to high
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'fan_speed': 'high' }})
|
||||
|
||||
if device['fan_speed'] == "high":
|
||||
# We just put the speed to high
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'fan_speed': 'low' }})
|
||||
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
if action == "set_mode":
|
||||
selected_mode = data
|
||||
|
||||
if selected_mode == {}:
|
||||
return {'status': 'failed', 'message': 'Please select a mode!'}, 200
|
||||
|
||||
if device['status'] == "off":
|
||||
return {'status': 'failed', 'message': 'Air Conditioniner must be on to change modes!'}, 200
|
||||
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'busy' }})
|
||||
|
||||
# Start thread because this action has waiting functions
|
||||
_thread.start_new_thread(AirConditioner.handleSetMode, ("Main Handle Set Mode Thread", 2, device, selected_mode))
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
if action == "set_temperature":
|
||||
selected_temperature = data
|
||||
|
||||
if selected_temperature == {}:
|
||||
return {'status': 'failed', 'message': 'Please select a temperature!'}, 200
|
||||
|
||||
if device['status'] == "off":
|
||||
return {'status': 'failed', 'message': 'Air Conditioning must be on to change target temperatures!'}, 200
|
||||
|
||||
new_selected_temperature = int(selected_temperature)
|
||||
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'busy' }})
|
||||
|
||||
# Start thread because this action has waiting functions
|
||||
_thread.start_new_thread(AirConditioner.handleSetTemperature, ("Main Handle Set Temperature Thread", 2, device, new_selected_temperature))
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
@staticmethod
|
||||
def handleSetTemperature(threadName, delay, device, temperature):
|
||||
print('Started Air Conditioner Set Termperature Thread!')
|
||||
|
||||
if device['target_temperature'] == temperature:
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'on' }})
|
||||
print('Exiting Air Conditioner Set Termperature Thread!')
|
||||
sys.exit()
|
||||
|
||||
if temperature > device['target_temperature']:
|
||||
temperature_direction = "up"
|
||||
new_temperature_degrees = temperature - device['target_temperature']
|
||||
|
||||
if temperature < device['target_temperature']:
|
||||
temperature_direction = "down"
|
||||
new_temperature_degrees = device['target_temperature'] - temperature
|
||||
|
||||
# Plus one to init temp change on ac
|
||||
for x in range(new_temperature_degrees + 1):
|
||||
EchoSerial.EchoSerial.send_commmand(device, temperature_direction)
|
||||
time.sleep(.3)
|
||||
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'on', 'target_temperature': temperature }})
|
||||
print('Exiting Air Conditioner Set Termperature Thread!')
|
||||
|
||||
@staticmethod
|
||||
def handleSetMode(threadName, delay, device, mode):
|
||||
print('Started Air Conditioner Set Mode Thread!')
|
||||
|
||||
if device['mode'] == mode:
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'on' }})
|
||||
print('Exiting Air Conditioner Set Mode Thread!')
|
||||
sys.exit()
|
||||
|
||||
# Goto base Pos (cooling)
|
||||
if device['mode'] == "cooling":
|
||||
#Do nothing, already in cooling mode (base pos)
|
||||
pass
|
||||
|
||||
if device['mode'] == "dehumidifying":
|
||||
# switch 2 times
|
||||
EchoSerial.EchoSerial.send_commmand(device, "mode")
|
||||
time.sleep(.3)
|
||||
EchoSerial.EchoSerial.send_commmand(device, "mode")
|
||||
time.sleep(.3)
|
||||
|
||||
if device['mode'] == "blowing":
|
||||
# switch 1 time
|
||||
EchoSerial.EchoSerial.send_commmand(device, "mode")
|
||||
time.sleep(.3)
|
||||
|
||||
# Do nothing, base pos is cooling
|
||||
if mode == "cooling":
|
||||
pass
|
||||
|
||||
if mode == "dehumidifying":
|
||||
# switch 1 time
|
||||
EchoSerial.EchoSerial.send_commmand(device, "mode")
|
||||
time.sleep(.3)
|
||||
|
||||
if mode == "blowing":
|
||||
# switch 2 times
|
||||
EchoSerial.EchoSerial.send_commmand(device, "mode")
|
||||
time.sleep(.3)
|
||||
EchoSerial.EchoSerial.send_commmand(device, "mode")
|
||||
time.sleep(.3)
|
||||
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'on', 'mode': mode }})
|
||||
print('Exiting Air Conditioner Set Mode Thread!')
|
161
echo-master/echo_controller/blinds.py
Normal file
161
echo-master/echo_controller/blinds.py
Normal file
@@ -0,0 +1,161 @@
|
||||
import datetime
|
||||
import time
|
||||
import sys
|
||||
import echo_serial.serial_controller as EchoSerial
|
||||
import echo_db.database as EchoDB
|
||||
import _thread
|
||||
|
||||
class Blinds:
|
||||
|
||||
@staticmethod
|
||||
def handle_action(device, action, data):
|
||||
actionData = device['actions'][action]
|
||||
|
||||
# Check if we send action too fast after last issued action
|
||||
actionNow = datetime.datetime.now()
|
||||
actionLast = device['last_used']
|
||||
lastIssued = (actionNow - actionLast).total_seconds()
|
||||
|
||||
if lastIssued < 2.0:
|
||||
return {'status': 'failed', 'message': 'Issued action too fast after last issued action!'}, 200
|
||||
|
||||
# Check if a thread is using the blinds, if so return.
|
||||
if device['status'] == "busy":
|
||||
return {'status': 'failed', 'message': 'Blinds are being controlled by Echo, Please wait till finished.'}, 200
|
||||
|
||||
# Check if we issued stop command and check if we are moving
|
||||
# Stop blinds if we are moving
|
||||
if action == "stop":
|
||||
if device['status'] == "go_down" or device['status'] == "go_up":
|
||||
return Blinds.stopActiveBlinds(device, action, data)
|
||||
else:
|
||||
return {'status': 'failed', 'message': 'Blinds are not moving!'}, 200
|
||||
|
||||
# Check if we are already going up or down
|
||||
# If we are, stop that action
|
||||
if device['status'] == "go_down" or device['status'] == "go_up":
|
||||
return Blinds.stopActiveBlinds(device, action, data)
|
||||
|
||||
# If we are requesting specific preset
|
||||
if action == "preset":
|
||||
selected_preset = data
|
||||
|
||||
if selected_preset == {}:
|
||||
return {'status': 'failed', 'message': 'Please select a preset!'}, 200
|
||||
|
||||
if selected_preset not in device['presets']:
|
||||
return {'status': 'failed', 'message': 'Preset does not exist!'}, 200
|
||||
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'busy' }})
|
||||
|
||||
# Start thread because this action has waiting functions
|
||||
_thread.start_new_thread(Blinds.handleBlindsPreset, ("Main Serial Thread", 2, device, selected_preset))
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
# If we are requesting action
|
||||
if action == "up" or action == "down":
|
||||
# Send Serial Command
|
||||
EchoSerial.EchoSerial.send_commmand(device, action)
|
||||
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'go_' + action }})
|
||||
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
# If we are requesting to set automatic time
|
||||
if action == "set_automatic_time":
|
||||
selected_auto_time = data
|
||||
|
||||
if selected_auto_time == {}:
|
||||
return {'status': 'failed', 'message': 'Please select a time!'}, 200
|
||||
|
||||
if selected_auto_time == "--:--":
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'automatic_open': False, 'automatic_open_time': '--:--' }})
|
||||
else:
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'automatic_open': True, 'automatic_open_time': selected_auto_time }})
|
||||
|
||||
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def stopActiveBlinds(device, action, data):
|
||||
if device['status'] == "go_down":
|
||||
EchoSerial.EchoSerial.send_commmand(device, "down")
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'custom' }})
|
||||
return {'status': 'success', 'message': 'Stopped blinds.'}, 200
|
||||
|
||||
if device['status'] == "go_up":
|
||||
EchoSerial.EchoSerial.send_commmand(device, "up")
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'custom' }})
|
||||
return {'status': 'success', 'message': 'Stopped blinds.'}, 200
|
||||
|
||||
|
||||
@staticmethod
|
||||
def handleBlindsPreset(threadname, delay, device, preset):
|
||||
print('Started Blinds Preset Thread!')
|
||||
presetData = device['presets'][preset]
|
||||
|
||||
# Check if we are already in preset position
|
||||
if device['status'] == "preset":
|
||||
if device['current_preset'] == preset:
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'custom' }})
|
||||
print('Exiting Blinds Preset Thread!')
|
||||
sys.exit()
|
||||
|
||||
# If custom goto open position
|
||||
if device['status'] == "custom":
|
||||
Blinds.setBlindsOpen(device)
|
||||
|
||||
# If device is already in preset position, check if we need to go to open position first
|
||||
# Or if we can skip that
|
||||
if device['status'] == "preset":
|
||||
if device['current_preset'] != "open":
|
||||
Blinds.setBlindsOpen(device)
|
||||
|
||||
if preset == "closed_ventilated":
|
||||
# Go down for 11 seconds
|
||||
EchoSerial.EchoSerial.send_commmand(device, 'down')
|
||||
time.sleep(17)
|
||||
EchoSerial.EchoSerial.send_commmand(device, 'down')
|
||||
|
||||
if preset == "open_ventilated":
|
||||
# Go down for 11 seconds
|
||||
EchoSerial.EchoSerial.send_commmand(device, 'down')
|
||||
time.sleep(11)
|
||||
EchoSerial.EchoSerial.send_commmand(device, 'down')
|
||||
|
||||
if preset == "open":
|
||||
# We already went to open position, no need to do it again
|
||||
pass
|
||||
|
||||
if preset == "closed":
|
||||
EchoSerial.EchoSerial.send_commmand(device, 'down')
|
||||
time.sleep(19)
|
||||
EchoSerial.EchoSerial.send_commmand(device, 'down')
|
||||
|
||||
# Update Database
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': 'preset', 'current_preset': preset }})
|
||||
print('Exiting Blinds Preset Thread!')
|
||||
|
||||
@staticmethod
|
||||
def setBlindsOpen(device):
|
||||
EchoSerial.EchoSerial.send_commmand(device, 'up')
|
||||
time.sleep(25)
|
||||
EchoSerial.EchoSerial.send_commmand(device, 'up')
|
||||
time.sleep(2)
|
31
echo-master/echo_controller/controller.py
Normal file
31
echo-master/echo_controller/controller.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import echo_controller.switch as Switch
|
||||
import echo_controller.sensor as Sensor
|
||||
import echo_controller.blinds as Blinds
|
||||
import echo_controller.air_conditioner as AirConditioner
|
||||
import echo_controller.led_strip as LedStrip
|
||||
|
||||
class Controller:
|
||||
|
||||
# These are all the device types with actions
|
||||
device_action_controls = {
|
||||
'switch' : Switch.Switch.handle_action,
|
||||
'sensor' : Sensor.Sensor.handle_action,
|
||||
'blinds' : Blinds.Blinds.handle_action,
|
||||
'airconditioner' : AirConditioner.AirConditioner.handle_action,
|
||||
'led_strip': LedStrip.LEDStrip.handle_action
|
||||
}
|
||||
|
||||
# These are all the output devices
|
||||
device_output_controls = {
|
||||
'sensor' : Sensor.Sensor.handle_data
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def handle_action(device, action, data = {}):
|
||||
device_type = device['type']
|
||||
return Controller.device_action_controls[device_type](device, action, data)
|
||||
|
||||
@staticmethod
|
||||
def handle_output_device(device, action, data):
|
||||
device_type = device['type']
|
||||
return Controller.device_output_controls[device_type](device, action, data)
|
75
echo-master/echo_controller/led_strip.py
Normal file
75
echo-master/echo_controller/led_strip.py
Normal file
@@ -0,0 +1,75 @@
|
||||
import datetime
|
||||
import time
|
||||
import sys
|
||||
import echo_serial.serial_controller as EchoSerial
|
||||
import echo_db.database as EchoDB
|
||||
import _thread
|
||||
|
||||
class LEDStrip:
|
||||
|
||||
@staticmethod
|
||||
def handle_action(device, action, data):
|
||||
actionData = device['actions'][action]
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
|
||||
# Check if we send action too fast after last issued action
|
||||
actionNow = datetime.datetime.now()
|
||||
actionLast = device['last_used']
|
||||
lastIssued = (actionNow - actionLast).total_seconds()
|
||||
|
||||
# if lastIssued < 2.0:
|
||||
# return {'status': 'failed', 'message': 'Issued action too fast after last issued action!'}, 200
|
||||
|
||||
# Check if a thread is using the blinds, if so return.
|
||||
if device['status'] == "busy":
|
||||
return {'status': 'failed', 'message': 'LED Strip is being controlled by Echo, Please wait till finished.'}, 200
|
||||
|
||||
# Stop blinds if we are moving
|
||||
if action == "off":
|
||||
EchoSerial.EchoSerial.send_commmand(device, 'clear_color')
|
||||
|
||||
# Update Database
|
||||
collection.update_one({'uuid': device['uuid']}, {
|
||||
"$set": { 'last_used': datetime.datetime.now(),
|
||||
"status": action
|
||||
}})
|
||||
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
if action == "on":
|
||||
EchoSerial.EchoSerial.send_commmand(device, 'set_color', device['current_color'])
|
||||
|
||||
# Update Database
|
||||
collection.update_one({'uuid': device['uuid']}, {
|
||||
"$set": { 'last_used': datetime.datetime.now(),
|
||||
"status": action
|
||||
}})
|
||||
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
if action == "set_color":
|
||||
EchoSerial.EchoSerial.send_commmand(device, 'clear_color', data)
|
||||
|
||||
# Update Database
|
||||
collection.update_one({'uuid': device['uuid']}, {
|
||||
"$set": { 'last_used': datetime.datetime.now(),
|
||||
"current_color": data
|
||||
}})
|
||||
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
if action == "automatic_movement":
|
||||
|
||||
if data == "on":
|
||||
# Update Database
|
||||
now_time = datetime.datetime.now()
|
||||
auto_shutdown = now_time + datetime.timedelta(minutes = 2)
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'automatic_movement': True, 'automatic_shutdown': auto_shutdown }})
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
if data == "off":
|
||||
# Update Database
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'automatic_movement': False }})
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
return {'status': 'failed', 'message': 'Setting not found!'}, 200
|
105
echo-master/echo_controller/sensor.py
Normal file
105
echo-master/echo_controller/sensor.py
Normal file
@@ -0,0 +1,105 @@
|
||||
import datetime
|
||||
import echo_serial.serial_controller as EchoSerial
|
||||
import echo_db.database as EchoDB
|
||||
from bson import json_util, ObjectId
|
||||
import json
|
||||
|
||||
import echo_controller.switch as Switch
|
||||
|
||||
class Sensor:
|
||||
|
||||
@staticmethod
|
||||
def handle_action(device, action, data):
|
||||
actionData = device['actions'][action]
|
||||
|
||||
#
|
||||
# Climate Sensors
|
||||
#
|
||||
|
||||
if action == "gather_climate_data":
|
||||
EchoSerial.EchoSerial.send_commmand(device, action)
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
if action == "get_climate_data":
|
||||
collection = EchoDB.EchoDB.database['ClimateLogs']
|
||||
data = collection.find().sort([('timestamp', -1)]).limit(1)
|
||||
data_json = json.loads(json_util.dumps(data))
|
||||
return {'status': 'success', 'message': actionData['message'], 'data': data_json}, 200
|
||||
|
||||
#
|
||||
# Light Sensors
|
||||
#
|
||||
|
||||
if action == "gather_light_data":
|
||||
EchoSerial.EchoSerial.send_commmand(device, action)
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
if action == "get_light_data":
|
||||
collection = EchoDB.EchoDB.database['LightLog']
|
||||
data = collection.find().sort([('timestamp', -1)]).limit(1)
|
||||
data_json = json.loads(json_util.dumps(data))
|
||||
return {'status': 'success', 'message': actionData['message'], 'data': data_json}, 200
|
||||
|
||||
#
|
||||
# Movement Sensors
|
||||
#
|
||||
|
||||
if action == "get_movment_data":
|
||||
collection = EchoDB.EchoDB.database['MovementLog']
|
||||
data = collection.find().sort([('timestamp', -1)]).limit(20)
|
||||
data_json = json.loads(json_util.dumps(data))
|
||||
return {'status': 'success', 'message': actionData['message'], 'data': data_json}, 200
|
||||
|
||||
@staticmethod
|
||||
def handle_data(device, action, data):
|
||||
#
|
||||
# Climate Sensors
|
||||
#
|
||||
|
||||
if action == 'climate_data':
|
||||
collection = EchoDB.EchoDB.database['ClimateLogs']
|
||||
climate_data = data[2].split(',')
|
||||
|
||||
logData = {
|
||||
'uuid': device['uuid'],
|
||||
'temperature': float(climate_data[0]),
|
||||
'humidity': float(climate_data[1]),
|
||||
'timestamp': datetime.datetime.now()
|
||||
}
|
||||
|
||||
collection.insert(logData)
|
||||
|
||||
#
|
||||
# Light Sensors
|
||||
#
|
||||
|
||||
if action == 'light_data':
|
||||
collection = EchoDB.EchoDB.database['LightLog']
|
||||
lightAmount = data[2]
|
||||
|
||||
logData = {
|
||||
'uuid': device['uuid'],
|
||||
'light_amount': int(lightAmount),
|
||||
'timestamp': datetime.datetime.now()
|
||||
}
|
||||
|
||||
collection.insert(logData)
|
||||
|
||||
#
|
||||
# Movement Sensors
|
||||
#
|
||||
|
||||
if action == 'movement_data':
|
||||
collection = EchoDB.EchoDB.database['MovementLog']
|
||||
typeMovement = data[2]
|
||||
|
||||
logData = {
|
||||
'uuid': device['uuid'],
|
||||
'type_movement': typeMovement,
|
||||
'timestamp': datetime.datetime.now()
|
||||
}
|
||||
|
||||
collection.insert(logData)
|
||||
|
||||
# Handle Automatic Lights
|
||||
Switch.Switch.handle_movement_switch()
|
79
echo-master/echo_controller/switch.py
Normal file
79
echo-master/echo_controller/switch.py
Normal file
@@ -0,0 +1,79 @@
|
||||
import datetime
|
||||
import echo_serial.serial_controller as EchoSerial
|
||||
import echo_db.database as EchoDB
|
||||
|
||||
class Switch:
|
||||
|
||||
@staticmethod
|
||||
def handle_action(device, action, data):
|
||||
actionData = device['actions'][action]
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
|
||||
if action == "automatic_movement":
|
||||
|
||||
if data == "on":
|
||||
# Update Database
|
||||
now_time = datetime.datetime.now()
|
||||
auto_shutdown = now_time + datetime.timedelta(minutes= 2)
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'automatic_movement': True, 'automatic_shutdown': auto_shutdown }})
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
if data == "off":
|
||||
# Update Database
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'automatic_movement': False }})
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
return {'status': 'failed', 'message': 'Setting not found!'}, 200
|
||||
|
||||
#Check if status is already the action
|
||||
if device['status'] == action:
|
||||
message = "Device is already in the requested state!"
|
||||
return {'status': 'failed', 'message': message}, 200
|
||||
|
||||
# Send Serial Command
|
||||
EchoSerial.EchoSerial.send_commmand(device, action)
|
||||
|
||||
# Update Database
|
||||
collection.update_one({'uuid': device['uuid']}, {"$set": { 'last_used': datetime.datetime.now(), 'status': action }})
|
||||
|
||||
return {'status': 'success', 'message': actionData['message']}, 200
|
||||
|
||||
|
||||
@staticmethod
|
||||
def handle_movement_switch():
|
||||
mainLightUUID = '9472-4f60'
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
|
||||
# Get Device (Main Light)
|
||||
mainLightDevice = collection.find_one({'uuid': mainLightUUID})
|
||||
|
||||
# Check if automatic movement mode of main light is enabled, else do nothing
|
||||
if mainLightDevice['automatic_movement'] == False:
|
||||
return
|
||||
|
||||
# Check if light levels are low enough to turn on light
|
||||
collectionLight = EchoDB.EchoDB.database['LightLog']
|
||||
data = collectionLight.find().sort([('timestamp', -1)]).limit(1)
|
||||
if data[0]['light_amount'] > 250:
|
||||
return;
|
||||
|
||||
# Light is already on, update automatic shutdown.
|
||||
if mainLightDevice['status'] == "on":
|
||||
now_time = datetime.datetime.now()
|
||||
auto_shutdown = now_time + datetime.timedelta(minutes= 2)
|
||||
collection.update_one({'uuid': mainLightUUID}, {"$set": { 'automatic_shutdown': auto_shutdown }})
|
||||
return
|
||||
|
||||
# Light is off, turn it on
|
||||
|
||||
# Send Serial Command
|
||||
EchoSerial.EchoSerial.send_commmand(mainLightDevice, "on")
|
||||
|
||||
# Auto shutdown time
|
||||
now_time = datetime.datetime.now()
|
||||
auto_shutdown = now_time + datetime.timedelta(minutes= 2)
|
||||
|
||||
# Update Database
|
||||
collection.update_one({'uuid': mainLightUUID}, {"$set": { 'last_used': datetime.datetime.now(), 'status': "on", 'automatic_shutdown': auto_shutdown }})
|
||||
|
||||
|
0
echo-master/echo_db/__init__.py
Normal file
0
echo-master/echo_db/__init__.py
Normal file
BIN
echo-master/echo_db/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
echo-master/echo_db/__pycache__/__init__.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_db/__pycache__/__init__.cpython-38.pyc
Normal file
BIN
echo-master/echo_db/__pycache__/__init__.cpython-38.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_db/__pycache__/database.cpython-37.pyc
Normal file
BIN
echo-master/echo_db/__pycache__/database.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_db/__pycache__/database.cpython-38.pyc
Normal file
BIN
echo-master/echo_db/__pycache__/database.cpython-38.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_db/__pycache__/devices.cpython-37.pyc
Normal file
BIN
echo-master/echo_db/__pycache__/devices.cpython-37.pyc
Normal file
Binary file not shown.
22
echo-master/echo_db/database.py
Normal file
22
echo-master/echo_db/database.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import pymongo
|
||||
import sys
|
||||
|
||||
class EchoDB:
|
||||
|
||||
# Connect to MongoDB
|
||||
try:
|
||||
print('Connecting to MongoDB Database...')
|
||||
mongo_client = pymongo.MongoClient('mongodb://admin:ASnick1AS@172.16.100.244:27017/?authSource=admin')
|
||||
print('Connected to MongoDB Database!')
|
||||
except:
|
||||
print('Error occured while connecting to MongoDB Database!')
|
||||
print(sys.exc_info()[0])
|
||||
quit()
|
||||
|
||||
# Select Database
|
||||
database = mongo_client['Echo']
|
||||
|
||||
# Create Indexes
|
||||
database['MovementLog'].create_index("timestamp", expireAfterSeconds=10)
|
||||
database['ClimateLog'].create_index("timestamp", expireAfterSeconds=10)
|
||||
database['LightLog'].create_index("timestamp", expireAfterSeconds=10)
|
0
echo-master/echo_scheduler/__init__.py
Normal file
0
echo-master/echo_scheduler/__init__.py
Normal file
BIN
echo-master/echo_scheduler/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
echo-master/echo_scheduler/__pycache__/__init__.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_scheduler/__pycache__/__init__.cpython-38.pyc
Normal file
BIN
echo-master/echo_scheduler/__pycache__/__init__.cpython-38.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_scheduler/__pycache__/scheduler.cpython-37.pyc
Normal file
BIN
echo-master/echo_scheduler/__pycache__/scheduler.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_scheduler/__pycache__/scheduler.cpython-38.pyc
Normal file
BIN
echo-master/echo_scheduler/__pycache__/scheduler.cpython-38.pyc
Normal file
Binary file not shown.
100
echo-master/echo_scheduler/scheduler.py
Normal file
100
echo-master/echo_scheduler/scheduler.py
Normal file
@@ -0,0 +1,100 @@
|
||||
import sys
|
||||
import _thread
|
||||
import datetime
|
||||
import time
|
||||
import schedule
|
||||
|
||||
import echo_controller.controller as Controller
|
||||
import echo_db.database as EchoDB
|
||||
|
||||
class EchoScheduler:
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def init():
|
||||
print('Starting Echo Scheduler Thread...')
|
||||
_thread.start_new_thread(EchoScheduler.scheduler, ("Main Scheduler Thread", 2, ))
|
||||
|
||||
@staticmethod
|
||||
def scheduler(threadname, delay):
|
||||
print('Echo Scheduler Thread started!')
|
||||
|
||||
# Schedule Tasks
|
||||
schedule.every(2).minutes.do(EchoScheduler.getClimateData)
|
||||
schedule.every(2).minutes.do(EchoScheduler.getLightData)
|
||||
schedule.every(1).minute.do(EchoScheduler.checkAutomaticShutdown)
|
||||
schedule.every(1).minute.do(EchoScheduler.checkAutomaticBlinds)
|
||||
|
||||
# collection_delete = EchoDB.EchoDB.database['ClimateLogs']
|
||||
# collection_delete.remove({})
|
||||
|
||||
while True:
|
||||
schedule.run_pending()
|
||||
time.sleep(1)
|
||||
|
||||
@staticmethod
|
||||
def getClimateData():
|
||||
# Get Device
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
device = collection.find_one({'uuid': 'aa50-48fd'})
|
||||
|
||||
# Call Action
|
||||
Controller.Controller.handle_action(device, "gather_climate_data")
|
||||
|
||||
print('Scheduler Gathered Climate Data')
|
||||
|
||||
@staticmethod
|
||||
def getLightData():
|
||||
# Get Device
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
device = collection.find_one({'uuid': 'be0c-4bc7'})
|
||||
|
||||
# Call Action
|
||||
Controller.Controller.handle_action(device, "gather_light_data")
|
||||
|
||||
print('Scheduler Gathered Light Data')
|
||||
|
||||
@staticmethod
|
||||
def checkAutomaticShutdown():
|
||||
# Get Device
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
device = collection.find_one({'uuid': '9472-4f60'})
|
||||
|
||||
# Check if light is on
|
||||
if device['status'] == "off":
|
||||
return;
|
||||
|
||||
# Check if automatic movement is enabled
|
||||
if device['automatic_movement'] == False:
|
||||
return;
|
||||
|
||||
# Check if date is current time is past device automatic shutdown time
|
||||
automatic_shutdown_time = device['automatic_shutdown']
|
||||
current_time = datetime.datetime.now()
|
||||
|
||||
if current_time > automatic_shutdown_time:
|
||||
Controller.Controller.handle_action(device, "off")
|
||||
print('Scheduler Turned off light')
|
||||
|
||||
@staticmethod
|
||||
def checkAutomaticBlinds():
|
||||
# Get current time
|
||||
now_time = datetime.datetime.now()
|
||||
now_hours = now_time.hour
|
||||
now_minutes = now_time.minute
|
||||
check_time = str(now_hours).zfill(2) + ":" + str(now_minutes).zfill(2)
|
||||
|
||||
# Get Device
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
device = collection.find_one({'uuid': 'b039-471a'})
|
||||
|
||||
# Check if automatic open is enabled
|
||||
if device['automatic_open'] == False:
|
||||
return;
|
||||
|
||||
automatic_open_time = device['automatic_open_time']
|
||||
|
||||
if automatic_open_time == check_time:
|
||||
Controller.Controller.handle_action(device, "preset", "open")
|
||||
print('Scheduler Opened Sunblinds')
|
0
echo-master/echo_serial/__init__.py
Normal file
0
echo-master/echo_serial/__init__.py
Normal file
BIN
echo-master/echo_serial/__pycache__/__init__.cpython-37.pyc
Normal file
BIN
echo-master/echo_serial/__pycache__/__init__.cpython-37.pyc
Normal file
Binary file not shown.
BIN
echo-master/echo_serial/__pycache__/__init__.cpython-38.pyc
Normal file
BIN
echo-master/echo_serial/__pycache__/__init__.cpython-38.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
122
echo-master/echo_serial/serial_controller.py
Normal file
122
echo-master/echo_serial/serial_controller.py
Normal file
@@ -0,0 +1,122 @@
|
||||
import serial
|
||||
import _thread
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
import echo_db.database as EchoDB
|
||||
import echo_controller.controller as Controller
|
||||
|
||||
class EchoSerial:
|
||||
|
||||
arduino = serial.Serial()
|
||||
allow_control = True
|
||||
|
||||
@staticmethod
|
||||
def init():
|
||||
try:
|
||||
print('Starting Serial Connection with arduino...')
|
||||
# Start Serial Connection
|
||||
EchoSerial.arduino.baudrate = 115200
|
||||
EchoSerial.arduino.port = '/dev/ttyACM0'
|
||||
EchoSerial.arduino.timeout = .1
|
||||
EchoSerial.arduino.open()
|
||||
|
||||
if not EchoSerial.arduino.is_open:
|
||||
print('Could not open Serial Connection with arduino!')
|
||||
|
||||
print('Serial Connection Opened with arduino!')
|
||||
print('Starting Serial Handling Thread...')
|
||||
_thread.start_new_thread(EchoSerial.handle_serial, ("Main Serial Thread", 2, ))
|
||||
except:
|
||||
print('Error Initializing Serial Controller!')
|
||||
print('Serial Error: ' + str(sys.exc_info()[0]))
|
||||
EchoSerial.allow_control = False
|
||||
|
||||
@staticmethod
|
||||
def handle_serial(threadname, delay):
|
||||
print('Serial Handling Thread Started!')
|
||||
while EchoSerial.arduino.isOpen():
|
||||
time.sleep(.02)
|
||||
try:
|
||||
data = EchoSerial.arduino.readline()[:-2]
|
||||
if data:
|
||||
# Parse Incoming Data > Decode to UTF-8
|
||||
parsed_data = data.decode("utf-8")
|
||||
|
||||
# Start new thread to handle the reponse
|
||||
_thread.start_new_thread(EchoSerial.handle_serial_data, ("Serial Response Handler Tread", 2, parsed_data))
|
||||
|
||||
except:
|
||||
print('Error Occured on Serial handling Thread!')
|
||||
print('Serial Error: ' + str(sys.exc_info()[0]))
|
||||
EchoSerial.allow_control = False
|
||||
EchoSerial.reopen_serial_connection()
|
||||
# _thread.interrupt_main()
|
||||
|
||||
@staticmethod
|
||||
def reopen_serial_connection():
|
||||
try:
|
||||
EchoSerial.arduino.close()
|
||||
except:
|
||||
print("Error closing serial connection")
|
||||
|
||||
while not EchoSerial.arduino.isOpen():
|
||||
try:
|
||||
EchoSerial.arduino.open()
|
||||
except:
|
||||
print("Error reopening serial connection")
|
||||
finally:
|
||||
time.sleep(1)
|
||||
|
||||
EchoSerial.allow_control = True
|
||||
print("Serial Connection Established!")
|
||||
|
||||
@staticmethod
|
||||
def handle_serial_data(threadNamee, delay, data):
|
||||
# Command Example:
|
||||
# 9472-4f60:temp_data:data
|
||||
# Data is if needed separated by ,
|
||||
print('Parsing Packet: ' + data)
|
||||
|
||||
# Remove packet Markers
|
||||
data = data[1:-1]
|
||||
|
||||
# Parse command
|
||||
parsed_data = data.split(':')
|
||||
|
||||
# Check if startup command
|
||||
if parsed_data[0] == "0":
|
||||
print('Echo Controller Ready!')
|
||||
return
|
||||
|
||||
# Check if startup command
|
||||
if parsed_data[0] == "1":
|
||||
print('Echo LED Controller Ready!')
|
||||
return
|
||||
|
||||
# Get Device
|
||||
collection = EchoDB.EchoDB.database['Devices']
|
||||
device = collection.find_one({'uuid': parsed_data[0]})
|
||||
|
||||
# Send to controller
|
||||
Controller.Controller.handle_output_device(device, parsed_data[1], parsed_data)
|
||||
|
||||
@staticmethod
|
||||
def send_serial(command):
|
||||
# Command Example:
|
||||
# 9472-4f60:get_data:data
|
||||
# data is if needed separated by ,
|
||||
EchoSerial.arduino.write(command.encode())
|
||||
|
||||
@staticmethod
|
||||
def send_commmand(device, action, value = "0"):
|
||||
serial_command = "<" + device['uuid'] + ":" + action + ":" + value + ">"
|
||||
print('Sending Packet: ' + serial_command)
|
||||
EchoSerial.send_serial(serial_command)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
6
echo-master/requirements.txt
Normal file
6
echo-master/requirements.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
Flask
|
||||
Flask-RESTful
|
||||
pymongo
|
||||
pyserial
|
||||
schedule
|
||||
flask-cors
|
Reference in New Issue
Block a user