Lots of changes

This commit is contained in:
manuel83 2018-11-04 00:47:26 +01:00
parent cdfd0fa42f
commit 1f38928b90
34 changed files with 1143 additions and 698 deletions

File diff suppressed because it is too large Load diff

14
Dockerfile Normal file
View file

@ -0,0 +1,14 @@
FROM python:3
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8080
CMD [ "python", "./run.py" ]

View file

@ -1 +1,9 @@
name: Manuel
name: CraftBeerPi
version: 4.1
port: 8080
username: cbpi
password: 123

View file

@ -74,9 +74,19 @@ def background_task(name, interval):
return real_decorator return real_decorator
def on_startup(name, order=0):
def real_decorator(func):
func.on_startup = True
func.name = name
func.order = order
return func
return real_decorator
def entry_exit(f): def entry_exit(f):
def new_f(): def new_f():
print("Entering", f.__name__)
f() f()
print("Exited", f.__name__)
return new_f return new_f

View file

@ -1,19 +1,20 @@
from aiohttp import web from aiohttp import web
from aiohttp_auth.auth.decorators import auth_required
from core.api.decorator import on_event, request_mapping from core.api.decorator import on_event, request_mapping, on_startup
from core.controller.crud_controller import CRUDController from core.controller.crud_controller import CRUDController
from core.controller.plugin_controller import PluginController
from core.database.model import ActorModel from core.database.model import ActorModel
from core.http_endpoints.http_api import HttpAPI from core.http_endpoints.http_api import HttpAPI
from core.plugin import PluginAPI
class ActorHttp(HttpAPI): class ActorHttp(HttpAPI):
count = 0
@request_mapping(path="/hallo", auth_required=False) @request_mapping(path="/hallo", auth_required=False)
async def hello_world(self, request) -> web.Response: async def hello_world(self, request) -> web.Response:
print("HALLO") self.count = self.count + 1
return web.Response(status=200, text="OK") return web.Response(status=200, text=str(self.count))
@request_mapping(path="/{id}/on", auth_required=False) @request_mapping(path="/{id}/on", auth_required=False)
async def http_on(self, request) -> web.Response: async def http_on(self, request) -> web.Response:
@ -27,7 +28,7 @@ class ActorHttp(HttpAPI):
class ActorController(ActorHttp, CRUDController, PluginAPI): class ActorController(ActorHttp, CRUDController, PluginController):
model = ActorModel model = ActorModel
@ -50,12 +51,22 @@ class ActorController(ActorHttp, CRUDController, PluginAPI):
if value.type in self.types: if value.type in self.types:
clazz = self.types[value.type]; clazz = self.types[value.type];
self.actors[id] = clazz(self.cbpi) self.actors[id] = clazz(self.cbpi)
print(value.type)
print("CACHE", self.cache)
print("ACTORS", self.actors)
@on_startup(name="actor_init", order=2)
async def lets_go1(self):
pass
@on_startup(name="actor_init", order=99)
async def lets_go2(self):
pass
@on_startup(name="actor_init", order=-1)
async def lets_go(self):
pass
@on_event(topic="actor/+/on") @on_event(topic="actor/+/on")
def on(self, id, power=100, **kwargs) -> None: def on(self, id, power=100, **kwargs) -> None:
print("ON-------------", id, power) print("ON-------------", id, power)
@ -70,8 +81,7 @@ class ActorController(ActorHttp, CRUDController, PluginAPI):
:param id: :param id:
:param kwargs: :param kwargs:
""" """
print("POWERED ON", id, kwargs) pass

View file

@ -1,9 +1,83 @@
import logging
import os
from importlib import import_module
from pprint import pprint from pprint import pprint
import aiohttp
import yaml
from aiohttp import web
from core.api.decorator import request_mapping
from core.api.property import Property from core.api.property import Property
from core.utils.utils import load_config, json_dumps
logger = logging.getLogger(__file__)
logging.basicConfig(level=logging.INFO)
class PluginController():
modules = {}
def __init__(self, cbpi):
self.cbpi = cbpi
self.cbpi.register(self, "/plugin")
@classmethod
async def load_plugin_list(self):
async with aiohttp.ClientSession() as session:
async with session.get('https://raw.githubusercontent.com/Manuel83/craftbeerpi-plugins/master/plugins.yaml') as resp:
if(resp.status == 200):
data = yaml.load(await resp.text())
return data
@classmethod
async def load_plugins(self):
for filename in os.listdir("./core/extension"):
if os.path.isdir("./core/extension/" + filename) is False or filename == "__pycache__":
continue
try:
logger.info("Trying to load plugin %s" % filename)
data = load_config("./core/extension/%s/config.yaml" % filename)
if(data.get("version") == 4):
self.modules[filename] = import_module("core.extension.%s" % (filename))
logger.info("Plugin %s loaded successful" % filename)
else:
logger.warning("Plguin %s is not supporting version 4" % filename)
except Exception as e:
logger.error(e)
@request_mapping(path="/", method="GET", auth_required=False)
async def get_plugins(self, request):
"""
---
description: This end-point allow to test that service is up.
tags:
- Health check
produces:
- text/plain
responses:
"200":
description: successful operation. Return "pong" text
"405":
description: invalid HTTP Method
"""
return web.json_response(await self.load_plugin_list(), dumps=json_dumps)
class PluginAPI():
def register(self, name, clazz) -> None: def register(self, name, clazz) -> None:
''' '''
Register a new actor type Register a new actor type

View file

@ -15,7 +15,7 @@ class SystemController():
@request_mapping("/jobs", method="GET", name="get_jobs", auth_required=True) @request_mapping("/jobs", method="GET", name="get_jobs", auth_required=True)
def get_all_jobs(self, request): def get_all_jobs(self, request):
scheduler = get_scheduler_from_app(self.cbpi.app) scheduler = get_scheduler_from_app(self.cbpi.app)
print(scheduler.active_count, scheduler.pending_limit)
for j in scheduler: for j in scheduler:
print(j) print(j)

View file

@ -1,5 +1,4 @@
import asyncio import asyncio
import importlib
import logging import logging
from os import urandom from os import urandom
@ -12,11 +11,13 @@ from aiohttp_swagger import setup_swagger
from aiojobs.aiohttp import setup, get_scheduler_from_app from aiojobs.aiohttp import setup, get_scheduler_from_app
from core.controller.actor_controller import ActorController from core.controller.actor_controller import ActorController
from core.controller.plugin_controller import PluginController
from core.controller.sensor_controller import SensorController from core.controller.sensor_controller import SensorController
from core.controller.system_controller import SystemController from core.controller.system_controller import SystemController
from core.database.model import DBModel from core.database.model import DBModel
from core.eventbus import EventBus from core.eventbus import EventBus
from core.http_endpoints.http_login import Login from core.http_endpoints.http_login import Login
from core.utils import *
from core.websocket import WebSocket from core.websocket import WebSocket
logger = logging.getLogger(__file__) logger = logging.getLogger(__file__)
@ -24,25 +25,29 @@ logging.basicConfig(level=logging.INFO)
class CraftBeerPi(): class CraftBeerPi():
def __init__(self): def __init__(self):
self.config = load_config("./config/config.yaml")
logger.info("Init CraftBeerPI") logger.info("Init CraftBeerPI")
policy = auth.SessionTktAuthentication(urandom(32), 60, include_ip=True) policy = auth.SessionTktAuthentication(urandom(32), 60, include_ip=True)
middlewares = [session_middleware(EncryptedCookieStorage(urandom(32))), auth.auth_middleware(policy)] middlewares = [session_middleware(EncryptedCookieStorage(urandom(32))), auth.auth_middleware(policy)]
self.app = web.Application(middlewares=middlewares) self.app = web.Application(middlewares=middlewares)
self.initializer = []
setup(self.app) setup(self.app)
self.bus = EventBus() self.bus = EventBus()
self.ws = WebSocket(self) self.ws = WebSocket(self)
self.actor = ActorController(self) self.actor = ActorController(self)
self.sensor = SensorController(self) self.sensor = SensorController(self)
self.plugin = PluginController(self)
self.system = SystemController(self) self.system = SystemController(self)
self.login = Login(self) self.login = Login(self)
def register_events(self, obj): def register_events(self, obj):
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "eventbus")]: for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "eventbus")]:
print(method.__getattribute__("topic"), method)
doc = None doc = None
if method.__doc__ is not None: if method.__doc__ is not None:
@ -68,6 +73,18 @@ class CraftBeerPi():
self.app.on_startup.append(spawn_job) self.app.on_startup.append(spawn_job)
def register_on_startup(self, obj):
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "on_startup")]:
name = method.__getattribute__("name")
order = method.__getattribute__("order")
self.initializer.append(dict(name=name, method=method, order=order))
def register_ws(self, obj): def register_ws(self, obj):
if self.ws is None: if self.ws is None:
return return
@ -80,6 +97,7 @@ class CraftBeerPi():
self.register_events(obj) self.register_events(obj)
self.register_ws(obj) self.register_ws(obj)
self.register_background_task(obj) self.register_background_task(obj)
self.register_on_startup(obj)
def register_http_endpoints(self, obj, subapp=None): def register_http_endpoints(self, obj, subapp=None):
routes = [] routes = []
@ -117,24 +135,51 @@ class CraftBeerPi():
else: else:
self.app.add_routes(routes) self.app.add_routes(routes)
async def _load_extensions(self, app): def _swagger_setup(self):
extension_list = ["core.extension.dummy"]
long_description = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus vehicula, metus et sodales fringilla, purus leo aliquet odio, non tempor ante urna aliquet nibh. Integer accumsan laoreet tincidunt. Vestibulum semper vehicula sollicitudin. Suspendisse dapibus neque vitae mattis bibendum. Morbi eu pulvinar turpis, quis malesuada ex. Vestibulum sed maximus diam. Proin semper fermentum suscipit. Duis at suscipit diam. Integer in augue elementum, auctor orci ac, elementum est. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas condimentum id arcu quis volutpat. Vestibulum sit amet nibh sodales, iaculis nibh eget, scelerisque justo.
Nunc eget mauris lectus. Proin sit amet volutpat risus. Aliquam auctor nunc sit amet feugiat tempus. Maecenas nec ex dolor. Nam fermentum, mauris ut suscipit varius, odio purus luctus mauris, pretium interdum felis sem vel est. Proin a turpis vitae nunc volutpat tristique ac in erat. Pellentesque consequat rhoncus libero, ac sollicitudin odio tempus a. Sed vestibulum leo erat, ut auctor turpis mollis id. Ut nec nunc ex. Maecenas eu turpis in nibh placerat ullamcorper ac nec dui. Integer ac lacus neque. Donec dictum tellus lacus, a vulputate justo venenatis at. Morbi malesuada tellus quis orci aliquet, at vulputate lacus imperdiet. Nulla eu diam quis orci aliquam vulputate ac imperdiet elit. Quisque varius mollis dolor in interdum.
"""
setup_swagger(self.app,
description=long_description,
title=self.config.get("name", "CraftBeerPi"),
api_version=self.config.get("version", ""),
contact="info@craftbeerpi.com")
for extension in extension_list:
logger.info("LOADING PUGIN %s" % extension)
my_module = importlib.import_module(extension)
my_module.setup(self)
def start(self): def start(self):
from pyfiglet import Figlet
f = Figlet(font='big')
print(f.renderText("%s %s" % (self.config.get("name"), self.config.get("version"))))
# self.cache["init"] = sorted(self.cache["init"], key=lambda k: k['order'])
async def init_database(app): async def init_database(app):
await DBModel.test_connection() await DBModel.test_connection()
async def init_controller(app): async def init_controller(app):
await self.actor.init() await self.actor.init()
async def load_plugins(app):
await PluginController.load_plugin_list()
await PluginController.load_plugins()
async def call_initializer(app):
self.initializer = sorted(self.initializer, key=lambda k: k['order'])
for i in self.initializer:
logger.info("CALL INITIALIZER %s - %s " % (i["name"], i["method"].__name__))
await i["method"]()
self.app.on_startup.append(init_database) self.app.on_startup.append(init_database)
self.app.on_startup.append(self._load_extensions) self.app.on_startup.append(call_initializer)
self.app.on_startup.append(init_controller) self.app.on_startup.append(init_controller)
setup_swagger(self.app) self.app.on_startup.append(load_plugins)
web.run_app(self.app) self._swagger_setup()
web.run_app(self.app, port=self.config.get("port", 8080))

View file

@ -33,7 +33,7 @@ class DBModel(object):
@classmethod @classmethod
async def test_connection(self): async def test_connection(self):
print("CREATE DATABSE")
async with aiosqlite.connect(TEST_DB) as db: async with aiosqlite.connect(TEST_DB) as db:
assert isinstance(db, aiosqlite.Connection) assert isinstance(db, aiosqlite.Connection)
@ -42,7 +42,7 @@ class DBModel(object):
@classmethod @classmethod
async def get_all(cls): async def get_all(cls):
print("GET ALL")
if cls.__as_array__ is True: if cls.__as_array__ is True:
result = [] result = []
else: else:
@ -113,7 +113,7 @@ class DBModel(object):
else: else:
data = data + (kwargs.get(f),) data = data + (kwargs.get(f),)
print(query, data)
cursor = await db.execute(query, data) cursor = await db.execute(query, data)
await db.commit() await db.commit()

View file

@ -64,7 +64,7 @@ class EventBus(object):
self.logger.info("EMIT EVENT %s", event) self.logger.info("EMIT EVENT %s", event)
for methods in self.iter_match(event): for methods in self.iter_match(event):
for f in methods: for f in methods:
print("METHOD: ", f)
f(**kwargs) f(**kwargs)
def iter_match(self, topic): def iter_match(self, topic):

View file

@ -1,10 +1,8 @@
from core.database.model import ActorModel import logging
from core.api.decorator import action, background_task
from core.api.property import Property
from core.api.actor import CBPiActor from core.api.actor import CBPiActor
import logging from core.api.decorator import action, background_task
from core.api.property import Property
class MyActor(CBPiActor): class MyActor(CBPiActor):
@ -36,7 +34,7 @@ class MyActor(CBPiActor):
return return
self.cfg = self.load_config() self.cfg = self.load_config()
print(self.cfg)
self.logger = logging.getLogger(__file__) self.logger = logging.getLogger(__file__)
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)

View file

@ -1 +1,2 @@
name: Maneul name: Manuel
version: 4

View file

@ -1,15 +1,15 @@
import logging import logging
from aiohttp import web from aiohttp import web
from aiojobs.aiohttp import get_scheduler_from_app
from core.api.decorator import request_mapping from core.api.decorator import request_mapping
from core.utils.utils import json_dumps from core.utils.utils import json_dumps
class HttpAPI(): class HttpAPI():
def __init__(self,cbpi): def __init__(self,cbpi):
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
self.logger.info("WOOHOO MY ACTOR")
self.cbpi =cbpi self.cbpi =cbpi
@request_mapping(path="/", auth_required=False) @request_mapping(path="/", auth_required=False)
@ -21,7 +21,6 @@ class HttpAPI():
id = int(request.match_info['id']) id = int(request.match_info['id'])
return web.json_response(await self.get_one(id), dumps=json_dumps) return web.json_response(await self.get_one(id), dumps=json_dumps)
@request_mapping(path="/{id}'", method="POST", auth_required=False) @request_mapping(path="/{id}'", method="POST", auth_required=False)
async def http_add_one(self, request): async def http_add_one(self, request):
id = request.match_info['id'] id = request.match_info['id']

View file

@ -1,10 +1,7 @@
import pathlib
from aiohttp import web from aiohttp import web
from aiohttp_auth import auth from aiohttp_auth import auth
from core.api.decorator import request_mapping from core.api.decorator import request_mapping
from core.utils.utils import load_config
class Login(): class Login():
@ -12,10 +9,9 @@ class Login():
def __init__(self,cbpi): def __init__(self,cbpi):
self.cbpi = cbpi self.cbpi = cbpi
self.cbpi.register(self) self.cbpi.register(self)
cfg = load_config(str(pathlib.Path('.') / 'config' / 'config.yaml'))
print("######", cfg)
self.db = {'user': 'password', 'super_user': 'super_password'} self.db = {cbpi.config.get("username", "cbpi"): cbpi.config.get("password", "cbpi")}
@request_mapping(path="/logout", name="Logout", method="GET", auth_required=True) @request_mapping(path="/logout", name="Logout", method="GET", auth_required=True)
async def logout_view(self, request): async def logout_view(self, request):
@ -26,7 +22,7 @@ class Login():
async def login_view(self, request): async def login_view(self, request):
params = await request.post() params = await request.post()
print(params.get('username', None), params.get('password', None))
user = params.get('username', None) user = params.get('username', None)
if (user in self.db and if (user in self.db and
params.get('password', None) == self.db[user]): params.get('password', None) == self.db[user]):

View file

@ -1,11 +1,10 @@
from aiojobs.aiohttp import get_scheduler_from_app from aiojobs.aiohttp import get_scheduler_from_app
from core.mqtt_matcher import MQTTMatcher
from hbmqtt.broker import Broker from hbmqtt.broker import Broker
from hbmqtt.client import MQTTClient from hbmqtt.client import MQTTClient
from hbmqtt.mqtt.constants import QOS_1, QOS_0 from hbmqtt.mqtt.constants import QOS_1, QOS_0
from typing import Callable from typing import Callable
from core.mqtt_matcher import MQTTMatcher
class MQTT(): class MQTT():
def __init__(self,cbpi): def __init__(self,cbpi):
@ -44,14 +43,14 @@ class MQTT():
def sysmsg(self, msg): def sysmsg(self, msg):
print("SYS", msg) pass
def ok_msg(self, msg): def ok_msg(self, msg):
self.count = self.count + 1 self.count = self.count + 1
print("MSFG", msg, self.count)
def publish(self, topic, message): def publish(self, topic, message):
print("PUSH NOW", topic)
self.cbpi.app.loop.create_task(self.client.publish(topic, str.encode(message), QOS_0)) self.cbpi.app.loop.create_task(self.client.publish(topic, str.encode(message), QOS_0))
def register_callback(self, func: Callable, topic) -> None: def register_callback(self, func: Callable, topic) -> None:
@ -64,12 +63,12 @@ class MQTT():
message = await self.client.deliver_message() message = await self.client.deliver_message()
matched = False matched = False
packet = message.publish_packet packet = message.publish_packet
print(message.topic)
#print(message.topic.split('/')) #print(message.topic.split('/'))
data = packet.payload.data.decode("utf-8") data = packet.payload.data.decode("utf-8")
for callback in self.matcher.iter_match(message.topic): for callback in self.matcher.iter_match(message.topic):
print("MATCH")
callback(data) callback(data)
matched = True matched = True
@ -84,7 +83,7 @@ class MQTT():
# await self.client.connect('mqtt://broker.hivemq.com:1883') # await self.client.connect('mqtt://broker.hivemq.com:1883')
for k, v in self.mqtt_methods.items(): for k, v in self.mqtt_methods.items():
print("############MQTT Subscribe:", k, v)
await self.client.subscribe([(k, QOS_1)]) await self.client.subscribe([(k, QOS_1)])
self.matcher[k] = v self.matcher[k] = v
await get_scheduler_from_app(app).spawn(self.on_message()) await get_scheduler_from_app(app).spawn(self.on_message())

View file

@ -38,7 +38,7 @@ class MQTTMatcher(object):
parent, node = node, node._children[k] parent, node = node, node._children[k]
lst.append((parent, k, node)) lst.append((parent, k, node))
# TODO # TODO
print(node._content)
if method is not None: if method is not None:
node._content = None node._content = None
else: else:
@ -58,9 +58,9 @@ class MQTTMatcher(object):
print("...",key, value) print("...",key, value)
node = self._root node = self._root
for sym in key.split('/'): for sym in key.split('/'):
print(sym)
node = node._children.setdefault(sym, self.Node()) node = node._children.setdefault(sym, self.Node())
print(node)
if not isinstance(node._content, list): if not isinstance(node._content, list):
#print("new array") #print("new array")
node._content = [] node._content = []
@ -155,7 +155,7 @@ if __name__ == "__main__":
m.register("actor/1/on", test_name) m.register("actor/1/on", test_name)
m.register("actor/1/on", test_name) m.register("actor/1/on", test_name)
print(m.get_callbacks("actor/1/on"))
m.unregister("actor/1/on") m.unregister("actor/1/on")

Binary file not shown.

View file

@ -0,0 +1 @@
from core.utils.utils import *

View file

@ -1,3 +1,5 @@
__all__ = ['load_config',"json_dumps"]
import json import json
from json import JSONEncoder from json import JSONEncoder
@ -9,7 +11,6 @@ from core.database.model import DBModel, ActorModel
def load_config(fname): def load_config(fname):
with open(fname, 'rt') as f: with open(fname, 'rt') as f:
data = yaml.load(f) data = yaml.load(f)
# TODO: add config validation
return data return data

View file

@ -1,6 +0,0 @@
import sys
from getpass import getpass
from passlib.hash import sha512_crypt
passwd = input() if not sys.stdin.isatty() else getpass()
print(sha512_crypt.encrypt(passwd))

View file

@ -1,34 +1,4 @@
2018-11-01 21:33:42,514,1,WOOHO 2018-11-04 00:34:55,389,1,WOOHO
2018-11-01 21:33:43,519,1,WOOHO 2018-11-04 00:35:14,956,1,WOOHO
2018-11-01 21:33:44,523,1,WOOHO 2018-11-04 00:35:15,960,1,WOOHO
2018-11-01 21:33:45,528,1,WOOHO 2018-11-04 00:35:16,962,1,WOOHO
2018-11-01 21:33:46,534,1,WOOHO
2018-11-01 21:33:47,538,1,WOOHO
2018-11-01 21:33:48,543,1,WOOHO
2018-11-01 21:33:49,548,1,WOOHO
2018-11-01 21:33:50,549,1,WOOHO
2018-11-01 21:33:51,554,1,WOOHO
2018-11-01 21:33:52,560,1,WOOHO
2018-11-01 21:33:53,561,1,WOOHO
2018-11-01 21:33:54,565,1,WOOHO
2018-11-01 21:33:55,570,1,WOOHO
2018-11-01 21:33:56,573,1,WOOHO
2018-11-01 21:33:57,576,1,WOOHO
2018-11-01 21:33:58,581,1,WOOHO
2018-11-01 21:33:59,582,1,WOOHO
2018-11-01 21:34:00,586,1,WOOHO
2018-11-01 21:34:01,588,1,WOOHO
2018-11-01 21:34:02,591,1,WOOHO
2018-11-01 21:34:03,596,1,WOOHO
2018-11-01 21:34:04,600,1,WOOHO
2018-11-01 21:34:05,604,1,WOOHO
2018-11-01 21:34:06,608,1,WOOHO
2018-11-01 21:34:07,612,1,WOOHO
2018-11-01 21:34:08,615,1,WOOHO
2018-11-01 21:34:09,623,1,WOOHO
2018-11-01 21:34:10,627,1,WOOHO
2018-11-01 21:34:11,631,1,WOOHO
2018-11-01 21:34:12,632,1,WOOHO
2018-11-01 21:34:13,633,1,WOOHO
2018-11-01 21:34:14,635,1,WOOHO
2018-11-01 21:34:15,640,1,WOOHO

View file

@ -1,60 +0,0 @@
2018-11-01 21:24:19,426,1,WOOHO
2018-11-01 21:24:20,431,1,WOOHO
2018-11-01 21:24:21,436,1,WOOHO
2018-11-01 21:24:22,442,1,WOOHO
2018-11-01 21:24:23,445,1,WOOHO
2018-11-01 21:24:24,450,1,WOOHO
2018-11-01 21:24:25,453,1,WOOHO
2018-11-01 21:24:26,457,1,WOOHO
2018-11-01 21:24:27,462,1,WOOHO
2018-11-01 21:24:28,466,1,WOOHO
2018-11-01 21:24:29,471,1,WOOHO
2018-11-01 21:24:30,475,1,WOOHO
2018-11-01 21:24:31,481,1,WOOHO
2018-11-01 21:24:32,484,1,WOOHO
2018-11-01 21:24:33,487,1,WOOHO
2018-11-01 21:24:34,491,1,WOOHO
2018-11-01 21:24:35,495,1,WOOHO
2018-11-01 21:24:36,499,1,WOOHO
2018-11-01 21:24:37,503,1,WOOHO
2018-11-01 21:24:38,506,1,WOOHO
2018-11-01 21:24:39,510,1,WOOHO
2018-11-01 21:24:40,515,1,WOOHO
2018-11-01 21:24:41,519,1,WOOHO
2018-11-01 21:24:42,522,1,WOOHO
2018-11-01 21:24:43,527,1,WOOHO
2018-11-01 21:24:44,532,1,WOOHO
2018-11-01 21:24:45,537,1,WOOHO
2018-11-01 21:24:46,542,1,WOOHO
2018-11-01 21:24:47,548,1,WOOHO
2018-11-01 21:24:48,554,1,WOOHO
2018-11-01 21:24:49,558,1,WOOHO
2018-11-01 21:24:50,563,1,WOOHO
2018-11-01 21:24:51,567,1,WOOHO
2018-11-01 21:24:52,573,1,WOOHO
2018-11-01 21:24:53,575,1,WOOHO
2018-11-01 21:24:54,578,1,WOOHO
2018-11-01 21:24:55,582,1,WOOHO
2018-11-01 21:24:56,583,1,WOOHO
2018-11-01 21:24:57,586,1,WOOHO
2018-11-01 21:24:58,589,1,WOOHO
2018-11-01 21:24:59,593,1,WOOHO
2018-11-01 21:25:00,597,1,WOOHO
2018-11-01 21:25:01,598,1,WOOHO
2018-11-01 21:25:02,600,1,WOOHO
2018-11-01 21:25:03,606,1,WOOHO
2018-11-01 21:25:04,612,1,WOOHO
2018-11-01 21:25:05,614,1,WOOHO
2018-11-01 21:25:06,616,1,WOOHO
2018-11-01 21:25:07,620,1,WOOHO
2018-11-01 21:25:08,624,1,WOOHO
2018-11-01 21:25:09,631,1,WOOHO
2018-11-01 21:25:10,634,1,WOOHO
2018-11-01 21:25:11,636,1,WOOHO
2018-11-01 21:25:12,640,1,WOOHO
2018-11-01 21:25:13,645,1,WOOHO
2018-11-01 21:25:14,649,1,WOOHO
2018-11-01 21:25:15,653,1,WOOHO
2018-11-01 21:25:16,657,1,WOOHO
2018-11-01 21:25:17,661,1,WOOHO
2018-11-01 21:25:18,665,1,WOOHO

View file

@ -1,60 +0,0 @@
2018-11-01 21:25:19,670,1,WOOHO
2018-11-01 21:25:20,673,1,WOOHO
2018-11-01 21:25:21,677,1,WOOHO
2018-11-01 21:25:22,682,1,WOOHO
2018-11-01 21:25:23,686,1,WOOHO
2018-11-01 21:25:24,690,1,WOOHO
2018-11-01 21:25:25,693,1,WOOHO
2018-11-01 21:25:26,698,1,WOOHO
2018-11-01 21:25:27,702,1,WOOHO
2018-11-01 21:25:28,707,1,WOOHO
2018-11-01 21:25:29,710,1,WOOHO
2018-11-01 21:25:30,713,1,WOOHO
2018-11-01 21:25:31,715,1,WOOHO
2018-11-01 21:25:32,719,1,WOOHO
2018-11-01 21:25:33,723,1,WOOHO
2018-11-01 21:25:34,725,1,WOOHO
2018-11-01 21:25:35,729,1,WOOHO
2018-11-01 21:25:36,733,1,WOOHO
2018-11-01 21:25:37,737,1,WOOHO
2018-11-01 21:25:38,742,1,WOOHO
2018-11-01 21:25:39,750,1,WOOHO
2018-11-01 21:25:40,756,1,WOOHO
2018-11-01 21:25:41,759,1,WOOHO
2018-11-01 21:25:42,764,1,WOOHO
2018-11-01 21:25:43,767,1,WOOHO
2018-11-01 21:25:44,773,1,WOOHO
2018-11-01 21:25:45,775,1,WOOHO
2018-11-01 21:25:46,780,1,WOOHO
2018-11-01 21:25:47,786,1,WOOHO
2018-11-01 21:25:48,788,1,WOOHO
2018-11-01 21:25:49,792,1,WOOHO
2018-11-01 21:25:50,796,1,WOOHO
2018-11-01 21:25:51,802,1,WOOHO
2018-11-01 21:25:52,805,1,WOOHO
2018-11-01 21:25:53,809,1,WOOHO
2018-11-01 21:25:54,811,1,WOOHO
2018-11-01 21:25:55,816,1,WOOHO
2018-11-01 21:25:56,818,1,WOOHO
2018-11-01 21:25:57,823,1,WOOHO
2018-11-01 21:25:58,827,1,WOOHO
2018-11-01 21:25:59,831,1,WOOHO
2018-11-01 21:26:00,835,1,WOOHO
2018-11-01 21:26:01,840,1,WOOHO
2018-11-01 21:26:02,843,1,WOOHO
2018-11-01 21:26:03,846,1,WOOHO
2018-11-01 21:26:04,852,1,WOOHO
2018-11-01 21:26:05,856,1,WOOHO
2018-11-01 21:26:06,860,1,WOOHO
2018-11-01 21:26:07,865,1,WOOHO
2018-11-01 21:26:08,870,1,WOOHO
2018-11-01 21:26:09,878,1,WOOHO
2018-11-01 21:26:10,883,1,WOOHO
2018-11-01 21:26:11,885,1,WOOHO
2018-11-01 21:26:12,889,1,WOOHO
2018-11-01 21:26:13,891,1,WOOHO
2018-11-01 21:26:14,892,1,WOOHO
2018-11-01 21:26:15,898,1,WOOHO
2018-11-01 21:26:16,903,1,WOOHO
2018-11-01 21:26:17,908,1,WOOHO
2018-11-01 21:26:18,911,1,WOOHO

View file

@ -1,12 +0,0 @@
2018-11-01 21:26:19,915,1,WOOHO
2018-11-01 21:26:20,922,1,WOOHO
2018-11-01 21:26:21,928,1,WOOHO
2018-11-01 21:26:22,933,1,WOOHO
2018-11-01 21:26:23,938,1,WOOHO
2018-11-01 21:26:24,944,1,WOOHO
2018-11-01 21:26:25,946,1,WOOHO
2018-11-01 21:26:26,950,1,WOOHO
2018-11-01 21:26:27,954,1,WOOHO
2018-11-01 21:26:28,958,1,WOOHO
2018-11-01 21:26:29,962,1,WOOHO
2018-11-01 21:26:30,966,1,WOOHO

View file

@ -1,60 +0,0 @@
2018-11-01 21:31:42,070,1,WOOHO
2018-11-01 21:31:43,075,1,WOOHO
2018-11-01 21:31:44,078,1,WOOHO
2018-11-01 21:31:45,082,1,WOOHO
2018-11-01 21:31:46,086,1,WOOHO
2018-11-01 21:31:47,090,1,WOOHO
2018-11-01 21:31:48,095,1,WOOHO
2018-11-01 21:31:49,099,1,WOOHO
2018-11-01 21:31:50,103,1,WOOHO
2018-11-01 21:31:51,106,1,WOOHO
2018-11-01 21:31:52,112,1,WOOHO
2018-11-01 21:31:53,116,1,WOOHO
2018-11-01 21:31:54,119,1,WOOHO
2018-11-01 21:31:55,124,1,WOOHO
2018-11-01 21:31:56,127,1,WOOHO
2018-11-01 21:31:57,131,1,WOOHO
2018-11-01 21:31:58,134,1,WOOHO
2018-11-01 21:31:59,137,1,WOOHO
2018-11-01 21:32:00,141,1,WOOHO
2018-11-01 21:32:01,142,1,WOOHO
2018-11-01 21:32:02,146,1,WOOHO
2018-11-01 21:32:03,150,1,WOOHO
2018-11-01 21:32:04,151,1,WOOHO
2018-11-01 21:32:05,155,1,WOOHO
2018-11-01 21:32:06,157,1,WOOHO
2018-11-01 21:32:07,161,1,WOOHO
2018-11-01 21:32:08,165,1,WOOHO
2018-11-01 21:32:09,169,1,WOOHO
2018-11-01 21:32:10,174,1,WOOHO
2018-11-01 21:32:11,179,1,WOOHO
2018-11-01 21:32:12,185,1,WOOHO
2018-11-01 21:32:13,191,1,WOOHO
2018-11-01 21:32:14,195,1,WOOHO
2018-11-01 21:32:15,197,1,WOOHO
2018-11-01 21:32:16,198,1,WOOHO
2018-11-01 21:32:17,202,1,WOOHO
2018-11-01 21:32:18,207,1,WOOHO
2018-11-01 21:32:19,209,1,WOOHO
2018-11-01 21:32:20,214,1,WOOHO
2018-11-01 21:32:21,218,1,WOOHO
2018-11-01 21:32:22,222,1,WOOHO
2018-11-01 21:32:23,228,1,WOOHO
2018-11-01 21:32:24,231,1,WOOHO
2018-11-01 21:32:25,234,1,WOOHO
2018-11-01 21:32:26,234,1,WOOHO
2018-11-01 21:32:27,240,1,WOOHO
2018-11-01 21:32:28,241,1,WOOHO
2018-11-01 21:32:29,245,1,WOOHO
2018-11-01 21:32:30,249,1,WOOHO
2018-11-01 21:32:31,254,1,WOOHO
2018-11-01 21:32:32,258,1,WOOHO
2018-11-01 21:32:33,261,1,WOOHO
2018-11-01 21:32:34,265,1,WOOHO
2018-11-01 21:32:35,268,1,WOOHO
2018-11-01 21:32:36,269,1,WOOHO
2018-11-01 21:32:37,274,1,WOOHO
2018-11-01 21:32:38,277,1,WOOHO
2018-11-01 21:32:39,282,1,WOOHO
2018-11-01 21:32:40,284,1,WOOHO
2018-11-01 21:32:41,289,1,WOOHO

View file

@ -1,60 +0,0 @@
2018-11-01 21:32:42,293,1,WOOHO
2018-11-01 21:32:43,299,1,WOOHO
2018-11-01 21:32:44,300,1,WOOHO
2018-11-01 21:32:45,304,1,WOOHO
2018-11-01 21:32:46,310,1,WOOHO
2018-11-01 21:32:47,314,1,WOOHO
2018-11-01 21:32:48,319,1,WOOHO
2018-11-01 21:32:49,322,1,WOOHO
2018-11-01 21:32:50,326,1,WOOHO
2018-11-01 21:32:51,330,1,WOOHO
2018-11-01 21:32:52,334,1,WOOHO
2018-11-01 21:32:53,338,1,WOOHO
2018-11-01 21:32:54,342,1,WOOHO
2018-11-01 21:32:55,345,1,WOOHO
2018-11-01 21:32:56,349,1,WOOHO
2018-11-01 21:32:57,354,1,WOOHO
2018-11-01 21:32:58,358,1,WOOHO
2018-11-01 21:32:59,363,1,WOOHO
2018-11-01 21:33:00,368,1,WOOHO
2018-11-01 21:33:01,371,1,WOOHO
2018-11-01 21:33:02,372,1,WOOHO
2018-11-01 21:33:03,377,1,WOOHO
2018-11-01 21:33:04,377,1,WOOHO
2018-11-01 21:33:05,382,1,WOOHO
2018-11-01 21:33:06,385,1,WOOHO
2018-11-01 21:33:07,386,1,WOOHO
2018-11-01 21:33:08,391,1,WOOHO
2018-11-01 21:33:09,395,1,WOOHO
2018-11-01 21:33:10,400,1,WOOHO
2018-11-01 21:33:11,403,1,WOOHO
2018-11-01 21:33:12,404,1,WOOHO
2018-11-01 21:33:13,408,1,WOOHO
2018-11-01 21:33:14,412,1,WOOHO
2018-11-01 21:33:15,416,1,WOOHO
2018-11-01 21:33:16,418,1,WOOHO
2018-11-01 21:33:17,422,1,WOOHO
2018-11-01 21:33:18,423,1,WOOHO
2018-11-01 21:33:19,427,1,WOOHO
2018-11-01 21:33:20,430,1,WOOHO
2018-11-01 21:33:21,435,1,WOOHO
2018-11-01 21:33:22,440,1,WOOHO
2018-11-01 21:33:23,446,1,WOOHO
2018-11-01 21:33:24,450,1,WOOHO
2018-11-01 21:33:25,451,1,WOOHO
2018-11-01 21:33:26,456,1,WOOHO
2018-11-01 21:33:27,459,1,WOOHO
2018-11-01 21:33:28,464,1,WOOHO
2018-11-01 21:33:29,466,1,WOOHO
2018-11-01 21:33:30,468,1,WOOHO
2018-11-01 21:33:31,470,1,WOOHO
2018-11-01 21:33:32,476,1,WOOHO
2018-11-01 21:33:33,477,1,WOOHO
2018-11-01 21:33:34,482,1,WOOHO
2018-11-01 21:33:35,487,1,WOOHO
2018-11-01 21:33:36,491,1,WOOHO
2018-11-01 21:33:37,495,1,WOOHO
2018-11-01 21:33:38,499,1,WOOHO
2018-11-01 21:33:39,504,1,WOOHO
2018-11-01 21:33:40,505,1,WOOHO
2018-11-01 21:33:41,512,1,WOOHO

View file

@ -0,0 +1,60 @@
2018-11-04 00:26:50,511,1,WOOHO
2018-11-04 00:26:51,516,1,WOOHO
2018-11-04 00:26:52,526,1,WOOHO
2018-11-04 00:26:53,530,1,WOOHO
2018-11-04 00:26:54,534,1,WOOHO
2018-11-04 00:26:55,537,1,WOOHO
2018-11-04 00:26:56,541,1,WOOHO
2018-11-04 00:26:57,542,1,WOOHO
2018-11-04 00:26:58,547,1,WOOHO
2018-11-04 00:26:59,552,1,WOOHO
2018-11-04 00:27:00,558,1,WOOHO
2018-11-04 00:27:01,561,1,WOOHO
2018-11-04 00:27:02,563,1,WOOHO
2018-11-04 00:27:03,567,1,WOOHO
2018-11-04 00:27:04,571,1,WOOHO
2018-11-04 00:27:05,572,1,WOOHO
2018-11-04 00:27:06,577,1,WOOHO
2018-11-04 00:27:07,579,1,WOOHO
2018-11-04 00:27:08,581,1,WOOHO
2018-11-04 00:27:09,582,1,WOOHO
2018-11-04 00:27:10,585,1,WOOHO
2018-11-04 00:27:11,588,1,WOOHO
2018-11-04 00:27:12,592,1,WOOHO
2018-11-04 00:27:13,596,1,WOOHO
2018-11-04 00:27:14,599,1,WOOHO
2018-11-04 00:27:15,604,1,WOOHO
2018-11-04 00:27:16,608,1,WOOHO
2018-11-04 00:27:17,614,1,WOOHO
2018-11-04 00:27:18,619,1,WOOHO
2018-11-04 00:27:19,624,1,WOOHO
2018-11-04 00:27:20,627,1,WOOHO
2018-11-04 00:27:21,629,1,WOOHO
2018-11-04 00:27:22,639,1,WOOHO
2018-11-04 00:27:23,642,1,WOOHO
2018-11-04 00:27:24,646,1,WOOHO
2018-11-04 00:27:25,649,1,WOOHO
2018-11-04 00:27:26,652,1,WOOHO
2018-11-04 00:27:27,656,1,WOOHO
2018-11-04 00:27:28,657,1,WOOHO
2018-11-04 00:27:29,659,1,WOOHO
2018-11-04 00:27:30,663,1,WOOHO
2018-11-04 00:27:31,668,1,WOOHO
2018-11-04 00:27:32,673,1,WOOHO
2018-11-04 00:27:33,679,1,WOOHO
2018-11-04 00:27:34,680,1,WOOHO
2018-11-04 00:27:35,686,1,WOOHO
2018-11-04 00:27:36,691,1,WOOHO
2018-11-04 00:27:37,692,1,WOOHO
2018-11-04 00:27:38,693,1,WOOHO
2018-11-04 00:27:39,696,1,WOOHO
2018-11-04 00:27:40,702,1,WOOHO
2018-11-04 00:27:41,708,1,WOOHO
2018-11-04 00:27:42,712,1,WOOHO
2018-11-04 00:27:43,715,1,WOOHO
2018-11-04 00:27:44,719,1,WOOHO
2018-11-04 00:27:45,723,1,WOOHO
2018-11-04 00:27:46,730,1,WOOHO
2018-11-04 00:27:47,735,1,WOOHO
2018-11-04 00:27:48,740,1,WOOHO
2018-11-04 00:27:49,744,1,WOOHO

View file

@ -0,0 +1,73 @@
2018-11-04 00:27:50,745,1,WOOHO
2018-11-04 00:27:51,756,1,WOOHO
2018-11-04 00:27:52,759,1,WOOHO
2018-11-04 00:27:53,764,1,WOOHO
2018-11-04 00:27:54,768,1,WOOHO
2018-11-04 00:27:55,772,1,WOOHO
2018-11-04 00:27:56,777,1,WOOHO
2018-11-04 00:27:57,782,1,WOOHO
2018-11-04 00:27:58,785,1,WOOHO
2018-11-04 00:27:59,791,1,WOOHO
2018-11-04 00:28:00,795,1,WOOHO
2018-11-04 00:28:01,799,1,WOOHO
2018-11-04 00:28:02,803,1,WOOHO
2018-11-04 00:28:03,807,1,WOOHO
2018-11-04 00:28:04,812,1,WOOHO
2018-11-04 00:28:05,817,1,WOOHO
2018-11-04 00:28:06,821,1,WOOHO
2018-11-04 00:28:07,826,1,WOOHO
2018-11-04 00:28:08,831,1,WOOHO
2018-11-04 00:28:09,836,1,WOOHO
2018-11-04 00:28:10,839,1,WOOHO
2018-11-04 00:28:11,840,1,WOOHO
2018-11-04 00:28:12,843,1,WOOHO
2018-11-04 00:28:13,847,1,WOOHO
2018-11-04 00:28:14,850,1,WOOHO
2018-11-04 00:28:15,855,1,WOOHO
2018-11-04 00:28:36,607,1,WOOHO
2018-11-04 00:28:37,610,1,WOOHO
2018-11-04 00:28:52,652,1,WOOHO
2018-11-04 00:28:53,656,1,WOOHO
2018-11-04 00:28:54,657,1,WOOHO
2018-11-04 00:28:55,663,1,WOOHO
2018-11-04 00:28:56,666,1,WOOHO
2018-11-04 00:28:57,667,1,WOOHO
2018-11-04 00:28:58,672,1,WOOHO
2018-11-04 00:28:59,675,1,WOOHO
2018-11-04 00:29:00,679,1,WOOHO
2018-11-04 00:29:01,681,1,WOOHO
2018-11-04 00:29:02,681,1,WOOHO
2018-11-04 00:29:03,687,1,WOOHO
2018-11-04 00:29:04,691,1,WOOHO
2018-11-04 00:29:05,694,1,WOOHO
2018-11-04 00:29:06,700,1,WOOHO
2018-11-04 00:29:07,704,1,WOOHO
2018-11-04 00:29:08,709,1,WOOHO
2018-11-04 00:29:09,713,1,WOOHO
2018-11-04 00:29:10,715,1,WOOHO
2018-11-04 00:29:11,716,1,WOOHO
2018-11-04 00:29:12,719,1,WOOHO
2018-11-04 00:29:13,722,1,WOOHO
2018-11-04 00:29:14,727,1,WOOHO
2018-11-04 00:29:15,733,1,WOOHO
2018-11-04 00:29:16,737,1,WOOHO
2018-11-04 00:29:17,740,1,WOOHO
2018-11-04 00:29:18,742,1,WOOHO
2018-11-04 00:29:19,745,1,WOOHO
2018-11-04 00:29:20,749,1,WOOHO
2018-11-04 00:29:21,756,1,WOOHO
2018-11-04 00:29:22,761,1,WOOHO
2018-11-04 00:29:23,766,1,WOOHO
2018-11-04 00:29:24,770,1,WOOHO
2018-11-04 00:29:25,775,1,WOOHO
2018-11-04 00:29:26,778,1,WOOHO
2018-11-04 00:29:27,782,1,WOOHO
2018-11-04 00:29:28,787,1,WOOHO
2018-11-04 00:29:29,789,1,WOOHO
2018-11-04 00:29:30,792,1,WOOHO
2018-11-04 00:29:31,795,1,WOOHO
2018-11-04 00:29:32,800,1,WOOHO
2018-11-04 00:29:33,803,1,WOOHO
2018-11-04 00:29:34,807,1,WOOHO
2018-11-04 00:29:35,812,1,WOOHO
2018-11-04 00:29:36,817,1,WOOHO

View file

@ -0,0 +1,59 @@
2018-11-04 00:29:37,823,1,WOOHO
2018-11-04 00:29:38,829,1,WOOHO
2018-11-04 00:29:39,832,1,WOOHO
2018-11-04 00:29:40,837,1,WOOHO
2018-11-04 00:29:41,843,1,WOOHO
2018-11-04 00:29:42,846,1,WOOHO
2018-11-04 00:29:43,852,1,WOOHO
2018-11-04 00:29:44,857,1,WOOHO
2018-11-04 00:29:45,858,1,WOOHO
2018-11-04 00:29:46,863,1,WOOHO
2018-11-04 00:29:47,865,1,WOOHO
2018-11-04 00:29:48,867,1,WOOHO
2018-11-04 00:29:49,869,1,WOOHO
2018-11-04 00:29:50,872,1,WOOHO
2018-11-04 00:29:51,878,1,WOOHO
2018-11-04 00:29:52,879,1,WOOHO
2018-11-04 00:29:53,881,1,WOOHO
2018-11-04 00:29:54,887,1,WOOHO
2018-11-04 00:29:55,891,1,WOOHO
2018-11-04 00:29:56,898,1,WOOHO
2018-11-04 00:29:57,903,1,WOOHO
2018-11-04 00:29:58,908,1,WOOHO
2018-11-04 00:29:59,911,1,WOOHO
2018-11-04 00:30:00,915,1,WOOHO
2018-11-04 00:30:01,920,1,WOOHO
2018-11-04 00:30:02,921,1,WOOHO
2018-11-04 00:30:03,925,1,WOOHO
2018-11-04 00:30:04,928,1,WOOHO
2018-11-04 00:30:05,933,1,WOOHO
2018-11-04 00:30:06,937,1,WOOHO
2018-11-04 00:30:07,940,1,WOOHO
2018-11-04 00:30:08,944,1,WOOHO
2018-11-04 00:30:09,948,1,WOOHO
2018-11-04 00:30:10,953,1,WOOHO
2018-11-04 00:30:11,957,1,WOOHO
2018-11-04 00:30:12,961,1,WOOHO
2018-11-04 00:30:13,965,1,WOOHO
2018-11-04 00:30:14,967,1,WOOHO
2018-11-04 00:30:15,970,1,WOOHO
2018-11-04 00:30:16,974,1,WOOHO
2018-11-04 00:30:17,978,1,WOOHO
2018-11-04 00:30:18,984,1,WOOHO
2018-11-04 00:30:19,990,1,WOOHO
2018-11-04 00:30:20,993,1,WOOHO
2018-11-04 00:30:21,995,1,WOOHO
2018-11-04 00:30:22,997,1,WOOHO
2018-11-04 00:30:24,001,1,WOOHO
2018-11-04 00:30:25,005,1,WOOHO
2018-11-04 00:30:26,007,1,WOOHO
2018-11-04 00:30:27,012,1,WOOHO
2018-11-04 00:30:28,014,1,WOOHO
2018-11-04 00:30:29,019,1,WOOHO
2018-11-04 00:30:30,022,1,WOOHO
2018-11-04 00:30:31,027,1,WOOHO
2018-11-04 00:30:32,032,1,WOOHO
2018-11-04 00:30:33,037,1,WOOHO
2018-11-04 00:30:34,042,1,WOOHO
2018-11-04 00:30:35,046,1,WOOHO
2018-11-04 00:30:36,051,1,WOOHO

View file

@ -0,0 +1,116 @@
2018-11-04 00:30:37,054,1,WOOHO
2018-11-04 00:30:38,060,1,WOOHO
2018-11-04 00:30:39,064,1,WOOHO
2018-11-04 00:30:40,070,1,WOOHO
2018-11-04 00:30:41,076,1,WOOHO
2018-11-04 00:30:42,079,1,WOOHO
2018-11-04 00:30:43,082,1,WOOHO
2018-11-04 00:30:44,087,1,WOOHO
2018-11-04 00:30:45,092,1,WOOHO
2018-11-04 00:30:46,093,1,WOOHO
2018-11-04 00:30:47,097,1,WOOHO
2018-11-04 00:30:48,100,1,WOOHO
2018-11-04 00:30:49,103,1,WOOHO
2018-11-04 00:30:50,106,1,WOOHO
2018-11-04 00:30:53,680,1,WOOHO
2018-11-04 00:30:54,683,1,WOOHO
2018-11-04 00:30:55,686,1,WOOHO
2018-11-04 00:30:56,688,1,WOOHO
2018-11-04 00:30:57,694,1,WOOHO
2018-11-04 00:30:58,696,1,WOOHO
2018-11-04 00:30:59,697,1,WOOHO
2018-11-04 00:31:00,700,1,WOOHO
2018-11-04 00:31:01,704,1,WOOHO
2018-11-04 00:31:02,707,1,WOOHO
2018-11-04 00:31:03,711,1,WOOHO
2018-11-04 00:31:04,714,1,WOOHO
2018-11-04 00:31:05,718,1,WOOHO
2018-11-04 00:31:06,719,1,WOOHO
2018-11-04 00:31:07,724,1,WOOHO
2018-11-04 00:31:08,730,1,WOOHO
2018-11-04 00:31:09,731,1,WOOHO
2018-11-04 00:31:10,736,1,WOOHO
2018-11-04 00:31:11,742,1,WOOHO
2018-11-04 00:31:12,746,1,WOOHO
2018-11-04 00:31:13,748,1,WOOHO
2018-11-04 00:31:14,754,1,WOOHO
2018-11-04 00:31:15,758,1,WOOHO
2018-11-04 00:31:16,762,1,WOOHO
2018-11-04 00:31:17,767,1,WOOHO
2018-11-04 00:31:18,770,1,WOOHO
2018-11-04 00:31:19,774,1,WOOHO
2018-11-04 00:31:20,780,1,WOOHO
2018-11-04 00:31:21,787,1,WOOHO
2018-11-04 00:31:22,788,1,WOOHO
2018-11-04 00:31:23,792,1,WOOHO
2018-11-04 00:31:24,796,1,WOOHO
2018-11-04 00:31:25,799,1,WOOHO
2018-11-04 00:31:26,804,1,WOOHO
2018-11-04 00:31:27,810,1,WOOHO
2018-11-04 00:31:28,814,1,WOOHO
2018-11-04 00:31:29,817,1,WOOHO
2018-11-04 00:31:30,823,1,WOOHO
2018-11-04 00:31:31,825,1,WOOHO
2018-11-04 00:31:32,830,1,WOOHO
2018-11-04 00:31:33,835,1,WOOHO
2018-11-04 00:31:34,841,1,WOOHO
2018-11-04 00:31:35,843,1,WOOHO
2018-11-04 00:31:36,845,1,WOOHO
2018-11-04 00:31:37,850,1,WOOHO
2018-11-04 00:31:38,854,1,WOOHO
2018-11-04 00:31:42,026,1,WOOHO
2018-11-04 00:31:43,030,1,WOOHO
2018-11-04 00:31:44,034,1,WOOHO
2018-11-04 00:31:45,037,1,WOOHO
2018-11-04 00:31:46,046,1,WOOHO
2018-11-04 00:31:47,051,1,WOOHO
2018-11-04 00:31:48,054,1,WOOHO
2018-11-04 00:31:49,059,1,WOOHO
2018-11-04 00:31:50,065,1,WOOHO
2018-11-04 00:31:51,070,1,WOOHO
2018-11-04 00:31:52,075,1,WOOHO
2018-11-04 00:31:53,082,1,WOOHO
2018-11-04 00:31:54,088,1,WOOHO
2018-11-04 00:31:55,093,1,WOOHO
2018-11-04 00:31:56,098,1,WOOHO
2018-11-04 00:31:57,102,1,WOOHO
2018-11-04 00:31:58,107,1,WOOHO
2018-11-04 00:31:59,110,1,WOOHO
2018-11-04 00:32:00,114,1,WOOHO
2018-11-04 00:32:01,120,1,WOOHO
2018-11-04 00:32:02,124,1,WOOHO
2018-11-04 00:32:03,130,1,WOOHO
2018-11-04 00:32:04,132,1,WOOHO
2018-11-04 00:32:05,136,1,WOOHO
2018-11-04 00:32:06,141,1,WOOHO
2018-11-04 00:32:07,142,1,WOOHO
2018-11-04 00:32:08,148,1,WOOHO
2018-11-04 00:32:09,149,1,WOOHO
2018-11-04 00:32:10,154,1,WOOHO
2018-11-04 00:32:11,161,1,WOOHO
2018-11-04 00:32:12,165,1,WOOHO
2018-11-04 00:32:13,171,1,WOOHO
2018-11-04 00:32:14,176,1,WOOHO
2018-11-04 00:32:15,180,1,WOOHO
2018-11-04 00:32:16,186,1,WOOHO
2018-11-04 00:32:17,191,1,WOOHO
2018-11-04 00:32:18,193,1,WOOHO
2018-11-04 00:32:19,196,1,WOOHO
2018-11-04 00:32:20,199,1,WOOHO
2018-11-04 00:32:21,204,1,WOOHO
2018-11-04 00:32:22,210,1,WOOHO
2018-11-04 00:32:23,213,1,WOOHO
2018-11-04 00:32:24,217,1,WOOHO
2018-11-04 00:32:25,223,1,WOOHO
2018-11-04 00:32:26,228,1,WOOHO
2018-11-04 00:32:27,232,1,WOOHO
2018-11-04 00:32:28,234,1,WOOHO
2018-11-04 00:32:29,238,1,WOOHO
2018-11-04 00:32:30,241,1,WOOHO
2018-11-04 00:32:31,244,1,WOOHO
2018-11-04 00:32:32,244,1,WOOHO
2018-11-04 00:32:33,247,1,WOOHO
2018-11-04 00:32:34,251,1,WOOHO
2018-11-04 00:32:35,254,1,WOOHO
2018-11-04 00:32:36,258,1,WOOHO
2018-11-04 00:32:37,264,1,WOOHO

View file

@ -0,0 +1,13 @@
2018-11-04 00:32:38,269,1,WOOHO
2018-11-04 00:32:39,274,1,WOOHO
2018-11-04 00:32:40,278,1,WOOHO
2018-11-04 00:32:41,280,1,WOOHO
2018-11-04 00:32:42,285,1,WOOHO
2018-11-04 00:32:43,290,1,WOOHO
2018-11-04 00:32:44,292,1,WOOHO
2018-11-04 00:32:45,295,1,WOOHO
2018-11-04 00:32:46,296,1,WOOHO
2018-11-04 00:32:47,301,1,WOOHO
2018-11-04 00:32:48,305,1,WOOHO
2018-11-04 00:32:49,309,1,WOOHO
2018-11-04 00:33:25,362,1,WOOHO

17
main.py
View file

@ -1,13 +1,12 @@
import aiohttp
import aiosqlite import aiosqlite
from aiohttp import web from aiohttp import web
from aiohttp_swagger import * from aiohttp_swagger import *
from aiojobs.aiohttp import setup, spawn, get_scheduler_from_app from aiojobs.aiohttp import setup, spawn, get_scheduler_from_app
from core.matcher import MQTTMatcher
from hbmqtt.broker import Broker from hbmqtt.broker import Broker
from hbmqtt.client import MQTTClient from hbmqtt.client import MQTTClient
from hbmqtt.mqtt.constants import QOS_1 from hbmqtt.mqtt.constants import QOS_1
from core.matcher import MQTTMatcher
from core.websocket import websocket_handler from core.websocket import websocket_handler
TEST_DB = "test.db" TEST_DB = "test.db"
@ -55,7 +54,7 @@ async def handle(request):
async def test_connection(): async def test_connection():
async with aiosqlite.connect(TEST_DB) as db: async with aiosqlite.connect(TEST_DB) as db:
print("DB OK")
assert isinstance(db, aiosqlite.Connection) assert isinstance(db, aiosqlite.Connection)
@ -76,19 +75,19 @@ async def listen_to_redis(app):
async def myjob(app): async def myjob(app):
while True: while True:
await asyncio.sleep(1) await asyncio.sleep(1)
print("JOB")
def ok_msg(msg): def ok_msg(msg):
print("OK", msg) pass
def ok_msg1(msg): def ok_msg1(msg):
print("OK1", msg) pass
def ok_msg2(msg): def ok_msg2(msg):
print("OK2", msg) pass
mqtt_methods = {"test": ok_msg, "test/+/ab": ok_msg1, "test/+": ok_msg2} mqtt_methods = {"test": ok_msg, "test/+/ab": ok_msg1, "test/+": ok_msg2}
@ -104,7 +103,7 @@ async def on_message():
data = packet.payload.data.decode("utf-8") data = packet.payload.data.decode("utf-8")
for callback in matcher.iter_match(message.topic): for callback in matcher.iter_match(message.topic):
print("MATCH")
callback(data) callback(data)
matched = True matched = True
@ -120,7 +119,7 @@ async def start_background_tasks(app):
async def start_broker(app): async def start_broker(app):
print(app)
await broker.start() await broker.start()
await c.connect('mqtt://localhost:1885') await c.connect('mqtt://localhost:1885')

View file

@ -1,13 +1,6 @@
from pprint import pprint
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from aiohttp import web
import json
from hbmqtt.broker import Broker
from core.craftbeerpi import CraftBeerPi from core.craftbeerpi import CraftBeerPi
from core.database.model import ActorModel
class MyAppTestCase(AioHTTPTestCase): class MyAppTestCase(AioHTTPTestCase):
@ -23,16 +16,16 @@ class MyAppTestCase(AioHTTPTestCase):
@unittest_run_loop @unittest_run_loop
async def test_example(self): async def test_example(self):
resp = await self.client.request("GET", "/actor/1/on") #resp = await self.client.request("GET", "/actor/1/on")
print(resp.status) #print(resp.status)
assert resp.status == 204 #assert resp.status == 204
for i in range(1000):
resp = await self.client.request("GET", "/actor/hallo")
resp = await self.client.request("GET", "/actor/") assert resp.status == 200
print(resp.status)
assert resp.status == 200
text = await resp.json() #text = await resp.json()
pprint(text) #pprint(text)
''' '''
resp = await self.client.request("GET", "/actor/2") resp = await self.client.request("GET", "/actor/2")
print(resp.status) print(resp.status)