Skip to content

Commit

Permalink
testsuite: working on generic http/mqtt controller emulatior receiving
Browse files Browse the repository at this point in the history
  • Loading branch information
psy0rz committed Jan 13, 2018
1 parent 57c6fbb commit 11a94aa
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 95 deletions.
97 changes: 96 additions & 1 deletion test/espcore.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,103 @@
### low level logging and protocol handling

import logging
import colorlog
import config
import paho.mqtt.client as mqtt
import json
import bottle
import threading
from queue import Queue, Empty

colorlog.basicConfig(level=logging.DEBUG)
log=logging.getLogger("TEST")


logging.getLogger("requests.packages.urllib3.connectionpool").setLevel(logging.ERROR)


### mqtt stuff
logging.getLogger("MQTT").debug("Connecting to {mqtt_broker}".format(mqtt_broker=config.mqtt_broker))

mqtt_client = mqtt.Client()
mqtt_client.connect(config.mqtt_broker, 1883, 60)
mqtt_client.loop_start()
mqtt_client.subscribe('#')

mqtt_messages=[]
def mqtt_on_message(client, userdata, message):
logging.getLogger("MQTT").debug("Received message '" + str(message.payload) + "' on topic '"
+ message.topic + "' with QoS " + str(message.qos))
mqtt_messages.append(message)

mqtt_client.on_message=mqtt_on_message


def mqtt_expect_json(topic, matches, timeout=60):
"""wait until a specific json message is received, and return it decoded. ignores all other messages"""

start_time=time.time()

logging.getLogger("MQTT").info("Waiting for json message on topic {topic}, with values {matches}".format(topic=topic, matches=matches))

# check mqtt results
while time.time()-start_time<timeout:
while mqtt_messages:
message=mqtt_messages.pop()
try:
#ignore decoding exceptions
payload=json.loads(message.payload.decode())
except:
continue

if message.topic == topic:
ok=True
for match in matches.items():
if not match[0] in payload or payload[match[0]]!=match[1]:
ok=False
if ok:
return(payload)
time.sleep(1)

raise(Exception("Timeout while expecting mqtt json message"))



### http server stuff.

# the http server just accepts everything and stores it in the http_requests queue
import bottle

http_requests = Queue()
@bottle.post('<filename:path>')
@bottle.get('<filename:path>')
def urlhandler(filename):
logging.getLogger("HTTP").debug(bottle.request.method+" "+str(dict(bottle.request.params)))
http_requests.put(bottle.request.copy())

http_thread=threading.Thread(target=bottle.run, kwargs=dict(host='0.0.0.0', port=config.http_port, reloader=False))
http_thread.daemon=True
http_thread.start()

def http_expect_request(path, matches, timeout=60):
"""wait until a specific path and paraters are request on the http server. ignores all other requests"""

start_time=time.time()

logging.getLogger("HTTP").info("Waiting for http request on path {path}, with values {matches}".format(path=path, matches=matches))

# check http results
while time.time()-start_time<timeout:
while True:
request=http_requests.get(block=True, timeout=timeout)
# logging.getLogger("HTTP").debug("Body: "+str(request.body.str))
if request.path == path:

ok=True
for match in matches.items():
if not match[0] in request.params or request.params[match[0]]!=match[1]:
ok=False
if ok:
return(request)
time.sleep(1)

raise(Exception("Timeout while expecting http message"))
85 changes: 83 additions & 2 deletions test/espeasy.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@
### Things like configging a controller or device via http
### I've created it in way that you can just copy/past form parameters from Chromium's header view

from espcore import *

import time


SENSOR_TYPE_SINGLE = 1
SENSOR_TYPE_TEMP_HUM = 2
SENSOR_TYPE_TEMP_BARO = 3
SENSOR_TYPE_TEMP_HUM_BARO = 4
SENSOR_TYPE_DUAL = 5
SENSOR_TYPE_TRIPLE = 6
SENSOR_TYPE_QUAD = 7
SENSOR_TYPE_SWITCH = 10
SENSOR_TYPE_DIMMER = 11
SENSOR_TYPE_LONG = 20
SENSOR_TYPE_WIND = 21

class EspEasy:

Expand All @@ -24,7 +40,7 @@ def control(self, **kwargs):
def controller_domoticz_mqtt(self, **kwargs):
"""config controller to use domoticz via mqtt"""

self._node.log.info("Config controller domoticz mqtt "+str(kwargs))
self._node.log.info("Configuring controller domoticz mqtt "+str(kwargs))
self._node.http_post(
twice=True, # needed for controllers and devices because of the way its implemented
page="controllers",
Expand All @@ -50,7 +66,7 @@ def controller_domoticz_mqtt(self, **kwargs):
def controller_domoticz_http(self, **kwargs):
"""config controller to use domoticz via http"""

self._node.log.info("Config controller domoticz http "+str(kwargs))
self._node.log.info("Configuring controller domoticz http "+str(kwargs))
self._node.http_post(
twice=True, # needed for controllers and devices because of the way its implemented
page="controllers",
Expand All @@ -70,6 +86,71 @@ def controller_domoticz_http(self, **kwargs):
""".format(**kwargs)
)

def recv_domoticz_http(self, sensor_type, timeout=60):
"""recv a domoticz http request from espeasy, and convert back to espeasy values"""

start_time=time.time()
logging.getLogger("domoticz http").info("Waiting for request with sensortype {sensor_type}".format(sensor_type=sensor_type))

# read and parse http requests
while time.time()-start_time<timeout:
request=http_requests.get(block=True, timeout=timeout)
if request.path == "/json.html":
if reuqest.params.get('param')=='udevice':
svalues=request.params.get('svalue').split(";")
if sensor_type==SENSOR_TYPE_SINGLE and len(svalues)==1:
return svalues
elif sensor_type==SENSOR_TYPE_DUAL and len(svalues)==2:
return svalues
elif sensor_type==SENSOR_TYPE_HUM and len(svalues)==3:
return svalues
elif sensor_type==SENSOR_TYPE_BARO and len(svalues)==5:
return [svalues[0], svalues[3]]
elif sensor_type==SENSOR_TYPE_TRIPLE and len(svalues)==3:
return svalues
elif sensor_type==SENSOR_TYPE_HUM_BARO and len(svalues)==5:
return [svalues[0],svalues[2], svalues[3]]
elif sensor_type==SENSOR_TYPE_QUAD and len(svalues)==4:
return svalues
elif sensor_type==SENSOR_TYPE_WIND and len(svalues)==5:
return [svalues[0], svalues[2], svalues[3]]

elif request.params.get('param')=='switchlight':
if sensor_type==SENSOR_TYPE_DIMMER or sensor_type == SENSOR_TYPE_SWITCH:
if request.params.get('switchcmd') == 'Off':
return [0]
elif request.params.get('switchcmd') == 'On':
return [1]
elif request.params.get('switchcmd') == 'Set Level':
return [request.params.get('level')]

raise(Exception("Timeout"))



def controller_thingspeak(self, **kwargs):

self._node.log.info("Configuring controller thingspeak "+str(kwargs))
self._node.http_post(
twice=True, # needed for controllers and devices because of the way its implemented
page="controllers",

params="""
index:{index}
""".format(**kwargs),

data="""
protocol:4
usedns:0
controllerip:{controllerip}
controllerport:{controllerport}
controlleruser:
controllerpassword:thingspeakkey1234
controllerenabled:on
""".format(**kwargs)
)


def device_p001(self, **kwargs):
self._node.log.info("Config device plugin p001 "+str(kwargs))

Expand Down
95 changes: 6 additions & 89 deletions test/esptest.py
Original file line number Diff line number Diff line change
@@ -1,104 +1,21 @@
#basic stuff needed in each test

from espeasy import *
#in each test just do: from esptest import *


# from espeasy import *
from node import *
from espeasy import *

import config
import time
import paho.mqtt.client as mqtt
import json
import bottle
import threading
from queue import Queue, Empty
from espcore import *


### mqtt stuff
logging.getLogger("MQTT").debug("Connecting to {mqtt_broker}".format(mqtt_broker=config.mqtt_broker))

mqtt_client = mqtt.Client()
mqtt_client.connect(config.mqtt_broker, 1883, 60)
mqtt_client.loop_start()
mqtt_client.subscribe('#')

mqtt_messages=[]
def mqtt_on_message(client, userdata, message):
logging.getLogger("MQTT").debug("Received message '" + str(message.payload) + "' on topic '"
+ message.topic + "' with QoS " + str(message.qos))
mqtt_messages.append(message)

mqtt_client.on_message=mqtt_on_message


def mqtt_expect_json(topic, matches, timeout=60):
"""wait until a specific json message is received, and return it decoded. ignores all other messages"""

start_time=time.time()

logging.getLogger("MQTT").info("Waiting for json message on topic {topic}, with values {matches}".format(topic=topic, matches=matches))

# check mqtt results
while time.time()-start_time<timeout:
while mqtt_messages:
message=mqtt_messages.pop()
try:
#ignore decoding exceptions
payload=json.loads(message.payload.decode())
except:
continue

if message.topic == topic:
ok=True
for match in matches.items():
if not match[0] in payload or payload[match[0]]!=match[1]:
ok=False
if ok:
return(payload)
time.sleep(1)

raise(Exception("Timeout while expecting mqtt json message"))


### create node objects and espeasy objects
node=[]
espeasy=[]

for n in config.nodes:
node.append(Node(n, "node"+str(len(node))))
espeasy.append(EspEasy(node[-1]))


### http server stuff.

# the http server just accepts everything and stores it in the http_requests queue
import bottle

http_requests = Queue()
@bottle.route('/<filename:path>')
def urlhandler(filename):
http_requests.put(bottle.request.copy())

http_thread=threading.Thread(target=bottle.run, kwargs=dict(host='0.0.0.0', port=config.http_port, reloader=False))
http_thread.daemon=True
http_thread.start()

def http_expect_request(path, matches, timeout=60):
"""wait until a specific path and paraters are request on the http server. ignores all other requests"""

start_time=time.time()

logging.getLogger("HTTP").info("Waiting for http request on path {path}, with values {matches}".format(path=path, matches=matches))

# check http results
while time.time()-start_time<timeout:
while not http_requests.empty():
request=http_requests.get()
if request.path == path:
ok=True
for match in matches.items():
if not match[0] in request.params or request.params[match[0]]!=match[1]:
ok=False
if ok:
return(request)
time.sleep(1)

raise(Exception("Timeout while expecting http message"))
13 changes: 10 additions & 3 deletions test/test002
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,20 @@ from esptest import *
# - correct values are send to domoticz via http
# - correct values are send to domoticz via mqtt

# espeasy[0].controller_thingspeak(index=1, controllerip=config.http_server, controllerport=config.http_port)

### config mqtt and the 2 devices
espeasy[0].controller_domoticz_http(index=1, controllerip=config.http_server, controllerport=config.http_port)
espeasy[0].device_p004(index=1, taskdevicepin1=2, plugin_004_dev=0, plugin_004_res=9, TDID1=1417)
espeasy[0].device_p004(index=2, taskdevicepin1=2, plugin_004_dev=1, plugin_004_res=9, TDID1=1418)
# espeasy[0].controller_domoticz_http(index=1, controllerip=config.http_server, controllerport=config.http_port)
# espeasy[0].device_p004(index=1, taskdevicepin1=2, plugin_004_dev=0, plugin_004_res=9, TDID1=1417)
# espeasy[0].device_p004(index=2, taskdevicepin1=2, plugin_004_dev=1, plugin_004_res=9, TDID1=1418)

print(espeasy[0].recv_domoticz_http(SENSOR_TYPE_SINGLE))


exit
#
#wait for request
temp1=http_expect_request("/update",{ 'apikey': 'thingspeakkey1234'}, timeout=10)
temp1=http_expect_request("/json.htm", { 'idx': '1417' }, timeout=10)
temp2=http_expect_request("/json.htm", { 'idx': '1418' }, timeout=10)

Expand Down

0 comments on commit 11a94aa

Please sign in to comment.