gate: start reorder

Signed-off-by: Thomas Klaehn <thomas.klaehn@u-blox.com>
This commit is contained in:
Thomas Klaehn
2017-03-30 11:05:31 +02:00
parent 0870736845
commit c1012382f2
27 changed files with 69 additions and 154 deletions

0
source/__init__.py Normal file
View File

View File

@@ -0,0 +1,24 @@
class DataBuffer(object):
def __init__(self, length):
self.__max = length
self.__data = []
def push(self, element):
if self.__max == 0:
return False
if len(self.__data) == self.__max:
_ = self.__data.pop(0)
self.__data.append(element)
return True
def average(self):
if len(self.__data) != self.__max:
return None
return sum(self.__data) / len(self.__data)
def length(self):
return len(self.__data)
def clear(self):
self.__data = []

View File

24
source/engine/__init__.py Normal file
View File

@@ -0,0 +1,24 @@
from gpio import Gpio
class Engine:
def __init__(self, gpio_1 = 13, gpio_2 = 19):
self.gpio_1 = Gpio(gpio_1)
self.gpio_2 = Gpio(gpio_2)
self.gpio_1.export()
self.gpio_1.direction(Gpio.DIRECTION_OUT)
self.gpio_2.export()
self.gpio_2.direction(Gpio.DIRECTION_OUT)
self.stop()
def stop(self):
self.gpio_1.set(0)
self.gpio_2.set(0)
def up(self):
self.gpio_1.set(1)
self.gpio_2.set(0)
def down(self):
self.gpio_1.set(0)
self.gpio_2.set(1)

0
source/gate/__init__.py Normal file
View File

45
source/gate/close.py Normal file
View File

@@ -0,0 +1,45 @@
'''
Created on Dec 23, 2016
@author: klaehn
'''
import sys
import time
from datetime import datetime as dt
from data_buffer import DataBuffer
from gate.gate_handler import GateHandler
from power_sensor import PowerSensor
POWER_SENSOR_I2C_BUS = 1
POWER_SENSOR_I2C_ADDRESS = 0x40
CONSECUTIVE_POWER_READS = 1000
MAX_ENGINE_POWER = {"up":330, "down":280}
def main(argv):
gate_handler = GateHandler()
power_sensor = PowerSensor(POWER_SENSOR_I2C_BUS, POWER_SENSOR_I2C_ADDRESS)
power_data = DataBuffer(CONSECUTIVE_POWER_READS)
gate_handler.close()
try:
while True:
rd = power_sensor.power_mw()
power_data.push(rd)
average = power_data.average()
print str(time.time()) + " " + str(rd)
if average != None:
if average > MAX_ENGINE_POWER["down"]:
gate_handler.stop()
# print "Gate successfully closed"
return 0
except KeyboardInterrupt:
gate_handler.stop()
# print "Closing procedure interrupted."
return 1
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))

View File

@@ -0,0 +1,24 @@
'''
Created on Dec 19, 2016
@author: klaehn
'''
from engine import Engine
class GateHandler(object):
"""Gate handler class"""
def __init__(self):
self.__engine = Engine(13, 19)
def open(self):
"""Open the gate"""
self.__engine.up()
def close(self):
"""Close the gate"""
self.__engine.down()
def stop(self):
"""Stop the Engine"""
self.__engine.stop()

176
source/gate/gate_state.py Normal file
View File

@@ -0,0 +1,176 @@
'''
Created on Dec 19, 2016
@author: klaehn
'''
from time import time, sleep
from communiate import Mqtt
from data_buffer import DataBuffer
from light_sensor.light_sensor import light_sensor
from gate.gate_handler import GateHandler
from power_sensor import PowerSensor
STATE_INIT = "init"
STATE_OPENED = "open"
STATE_CLOSED = "close"
STATE_OPENING = "opening"
STATE_CLOSING = "closing"
STATE_ERROR = "error"
LIGHT_READ_DELAY_S = 30
LIGHT_CONSECUTIVE_READS = 10
LIGHT_LX_THRESHOLD = {"open":10, "close":5}
MQTT_HOST = "proxy"
MQTT_TOPIC = "outdoor/chickenhouse/gate"
LIGHT_SENSOR_I2C_BUS = 1
LIGHT_SENSOR_I2C_ADDRESS = 0x23
POWER_SENSOR_I2C_BUS = 1
POWER_SENSOR_I2C_ADDRESS = 0x40
POWER_CONSECUTIVE_READS = 1000
MAX_ENGINE_POWER = {"up":330, "down":280}
MAX_GATE_RUNTIME = {"open":300, "close":300}
MIN_GATE_RUNTIME = {"open":10, "close":10}
class GateState(object):
def __init__(self):
self.__state_handler = {STATE_INIT:self.__init_handler, \
STATE_OPENED:self.__opened_handler, \
STATE_CLOSED:self.__closed_handler, \
STATE_OPENING:self.__opening_handler, \
STATE_CLOSING:self.__closing_handler, \
STATE_ERROR:self.__error_handler}
self.__next_state = "init"
self.__last_state = "error"
self.__light_sensor = light_sensor(LIGHT_SENSOR_I2C_BUS, \
LIGHT_SENSOR_I2C_ADDRESS)
self.__light_data = DataBuffer(LIGHT_CONSECUTIVE_READS)
self.__comserver = Mqtt(MQTT_HOST)
self.__gate_handler = GateHandler()
self.__power_sensor = PowerSensor(POWER_SENSOR_I2C_BUS, \
POWER_SENSOR_I2C_ADDRESS)
self.__power_data = DataBuffer(POWER_CONSECUTIVE_READS)
self.__gate_move_timeout = 0
self.__light_read_timeout = 0
self.__error_count = 0
self.__runtime_open = 0
self.__runtime_close = 0
def poll(self):
current_time = time()
if current_time >= self.__light_read_timeout:
self.__light_read_timeout = current_time + LIGHT_READ_DELAY_S
self.__light_data.push(self.__light_sensor.read())
self.__state_handler[self.__next_state](self.__light_data.average())
def __update_state(self, new_state):
self.__last_state = self.__next_state
self.__next_state = new_state
def __is_transition(self):
if self.__last_state != self.__next_state:
return True
return False
def __init_handler(self, light_avg):
'''
In init we don't know anything neither about gate state nor about
light. So first we try to reach STATE_CLOSED.
'''
#pylint: disable=unused-argument
self.__comserver.connect()
self.__comserver.transmit(MQTT_TOPIC, str(time()) + \
" gate gard initiated")
self.__comserver.disconnect()
self.__update_state(STATE_OPENING)
def __opened_handler(self, light_avg):
next_state = self.__next_state
if self.__is_transition():
self.__gate_handler.close()
sleep(5)
self.__gate_handler.stop()
self.__comserver.transmit(MQTT_TOPIC, str(time()) + " Opened " + \
str(self.__power_data.average()) + " mW")
self.__power_data.clear()
if light_avg <= LIGHT_LX_THRESHOLD["close"]:
next_state = STATE_CLOSING
self.__update_state(next_state)
def __closed_handler(self, light_avg):
next_state = self.__next_state
if self.__is_transition():
self.__gate_handler.open()
sleep(5)
self.__gate_handler.stop()
self.__comserver.transmit(MQTT_TOPIC, str(time()) + " Closed " + \
str(self.__power_data.average()) + " mW")
self.__power_data.clear()
if light_avg > LIGHT_LX_THRESHOLD["open"]:
next_state = STATE_OPENING
self.__update_state(next_state)
def __opening_handler(self, light_avg):
next_state = self.__next_state
if self.__is_transition():
self.__runtime_open = time() + MIN_GATE_RUNTIME["open"]
self.__gate_handler.open()
self.__gate_move_timeout = time() + MAX_GATE_RUNTIME["open"]
self.__comserver.transmit(MQTT_TOPIC, str(time()) + \
" Opening " + str(light_avg) + " lx")
if time() > self.__gate_move_timeout:
next_state = STATE_ERROR
else:
self.__power_data.push(self.__power_sensor.power_mw())
current_avg = self.__power_data.average()
if current_avg != None:
if current_avg > MAX_ENGINE_POWER["up"]:
if time() > self.__runtime_open:
next_state = STATE_OPENED
self.__update_state(next_state)
def __closing_handler(self, light_avg):
next_state = self.__next_state
if self.__is_transition():
self.__runtime_close = time() + MIN_GATE_RUNTIME["close"]
self.__gate_handler.close()
self.__gate_move_timeout = time() + MAX_GATE_RUNTIME["close"]
self.__comserver.transmit(MQTT_TOPIC, str(time()) + \
" Closing " + str(light_avg) + " lx")
if time() > self.__gate_move_timeout:
next_state = STATE_ERROR
else:
self.__power_data.push(self.__power_sensor.power_mw())
current_avg = self.__power_data.average()
if current_avg != None:
if current_avg > MAX_ENGINE_POWER["down"]:
if time() > self.__runtime_close:
next_state = STATE_CLOSED
self.__update_state(next_state)
def __error_handler(self, light_avg):
#pylint: disable=unused-argument
if self.__is_transition():
self.__gate_handler.stop()
self.__comserver.transmit(MQTT_TOPIC, str(time()) + \
" Error handler!!!")
self.__update_state(STATE_INIT)

18
source/gate/light.py Normal file
View File

@@ -0,0 +1,18 @@
'''
Created on Dec 24, 2016
@author: tkl
'''
import sys
import time
from light_sensor.light_sensor import light_sensor
import mqtt
def main():
conn = mqtt.Mqtt(hostname='proxy')
light = light_sensor(1, 0x23)
conn.transmit("outdoor/chickenhouse/sensors/light", str(int(time.time())) + " " + \
str(light.read()) + " lx")
if __name__ == "__main__":
sys.exit(main())

45
source/gate/open.py Normal file
View File

@@ -0,0 +1,45 @@
'''
Created on Dec 23, 2016
@author: klaehn
'''
import sys
import time
from datetime import datetime as dt
from data_buffer import DataBuffer
from gate.gate_handler import GateHandler
from power_sensor import PowerSensor
POWER_SENSOR_I2C_BUS = 1
POWER_SENSOR_I2C_ADDRESS = 0x40
CONSECUTIVE_POWER_READS = 1000
MAX_ENGINE_POWER = {"up":330, "down":290}
def main(argv):
gate_handler = GateHandler()
power_sensor = PowerSensor(POWER_SENSOR_I2C_BUS, POWER_SENSOR_I2C_ADDRESS)
power_data = DataBuffer(CONSECUTIVE_POWER_READS)
gate_handler.open()
try:
while True:
rd = power_sensor.power_mw()
power_data.push(rd)
average = power_data.average()
print str(time.time()) + " " + str(rd)
if average != None:
if average > MAX_ENGINE_POWER["up"]:
gate_handler.stop()
# print "Gate successfully opened"
return 0
except KeyboardInterrupt:
gate_handler.stop()
print "Closing procedure interrupted."
return 1
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))

22
source/gate_guard.py Normal file
View File

@@ -0,0 +1,22 @@
'''
Created on Dec 19, 2016
@author: klaehn
'''
import sys
import time
from gate.gate_state import GateState
def main():
gate_state = GateState()
try:
while True:
gate_state.poll()
time.sleep(0.001)
except KeyboardInterrupt:
print "key exit"
return None
if __name__ == "__main__":
sys.exit(main())

View File

View File

@@ -0,0 +1,11 @@
import smbus
class light_sensor:
def __init__(self, bus = 1, addr = 0x23):
self.__i2c_device = bus
self.__i2c_addr = addr
self.__i2c_device = smbus.SMBus(self.__i2c_device)
def read(self):
data = self.__i2c_device.read_i2c_block_data(self.__i2c_addr, 0x10)
return int(round((data[0] * 256 + data[1]) / 1.2, 0))

View File

@@ -0,0 +1,49 @@
'''
Created on Dec 19, 2016
@author: klaehn
'''
import smbus
class PowerSensor(object):
'''
Power sensor wrapper
'''
def __init__(self, bus = 1, addr = 0x40):
self.__bus = smbus.SMBus(bus)
self.__addr = addr
value = [(0x1000 >> 8) & 0xFF, 0x1000 & 0xFF]
self.__bus.write_i2c_block_data(self.__addr, 0x05, value)
config = 0x2000 | 0x1800 | 0x0400 | 0x0018 | 0x0007
value = [(config >> 8) & 0xFF, config & 0xFF]
self.__bus.write_i2c_block_data(self.__addr, 0x00, value)
def shunt_voltage_mv(self):
''' Read the voltage at the shunt resistor [mV] '''
data = self.__bus.read_i2c_block_data(self.__addr, 0x01)
voltage = data[0] * 256 + data[1]
return voltage * 0.01
def current_ma(self):
''' Read the current [mA] '''
data = self.__bus.read_i2c_block_data(self.__addr, 0x04)
if data[0] >> 7 == 1:
current = data[0] * 256 + data[1]
if current & (1 << 15):
current = current - (1 << 16)
else:
current = (data[0] << 8) | (data[1])
return current / 10
def power_mw(self):
''' Read the power [mW] '''
data = self.__bus.read_i2c_block_data(self.__addr, 0x03)
if data[0] >> 7 == 1:
power = data[0] * 256 + data[1]
if power & (1 << 15):
power = power - (1 << 16)
else:
power = (data[0] << 8) | (data[1])
return power / 2