test cases extended

This commit is contained in:
manuel83 2019-01-02 21:20:44 +01:00
parent b800fed933
commit 1d85dc7c15
57 changed files with 3161 additions and 2496 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,239 +1,13 @@
import json
import logging import logging
from asyncio import Future from asyncio import Future
from aiohttp import web
from cbpi_api import * from cbpi_api import *
from core.controller.crud_controller import CRUDController from core.controller.crud_controller import CRUDController
from core.database.model import ActorModel from core.database.model import ActorModel
from core.http_endpoints.http_api import HttpAPI
from utils.encoder import ComplexEncoder
auth = False
class ActorHttp(HttpAPI):
@request_mapping(path="/types", auth_required=False)
async def get_types(self, request):
"""
---
description: Get all actor types
tags:
- Actor
responses:
"200":
description: successful operation
"""
return await super().get_types(request)
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request):
"""
---
description: Switch actor on
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
return await super().http_get_all(request)
@request_mapping(path="/{id:\d+}", auth_required=False)
async def http_get_one(self, request):
"""
---
description: Get one Actor
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
return await super().http_get_one(request)
@request_mapping(path="/", method="POST", auth_required=False)
async def http_add(self, request):
"""
---
description: Get one Actor
tags:
- Actor
parameters:
- in: body
name: body
description: Created an actor
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
type: object
responses:
"204":
description: successful operation
"""
return await super().http_add(request)
@request_mapping(path="/{id}", method="PUT", auth_required=False)
async def http_update(self, request):
"""
---
description: Update an actor
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
- in: body
name: body
description: Update an actor
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
type: object
responses:
"200":
description: successful operation
"""
return await super().http_update(request)
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
async def http_delete_one(self, request):
"""
---
description: Delete an actor
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
return await super().http_delete_one(request)
@request_mapping(path="/{id:\d+}/on", method="POST", auth_required=auth)
async def http_on(self, request) -> web.Response:
"""
---
description: Switch actor on
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
id = int(request.match_info['id'])
result = await self.cbpi.bus.fire(topic="actor/%s/switch/on" % id, id=id, power=99)
for key, value in result.results.items():
pass
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/off", method="POST", auth_required=auth) class ActorController(CRUDController):
async def http_off(self, request) -> web.Response:
"""
---
description: Switch actor off
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
id = int(request.match_info['id'])
await self.cbpi.bus.fire(topic="actor/%s/off" % id, id=id)
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/toggle", method="POST", auth_required=auth)
async def http_toggle(self, request) -> web.Response:
"""
---
description: Toogle an actor on or off
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
id = int(request.match_info['id'])
await self.cbpi.bus.fire(topic="actor/%s/toggle" % id, id=id)
return web.Response(status=204)
class ActorController(ActorHttp, CRUDController):
''' '''
The main actor controller The main actor controller
''' '''
@ -244,21 +18,16 @@ class ActorController(ActorHttp, CRUDController):
self.cbpi = cbpi self.cbpi = cbpi
self.state = False; self.state = False;
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
self.cbpi.register(self, "/actor") self.cbpi.register(self)
self.types = {} self.types = {}
self.actors = {} self.actors = {}
def info(self):
return json.dumps(dict(name="ActorController", types=self.types), cls=ComplexEncoder)
async def init(self): async def init(self):
''' """
This method initializes all actors during startup. It creates actor instances This method initializes all actors during startup. It creates actor instances
:return: :return:
''' """
await super(ActorController, self).init() await super(ActorController, self).init()
for id, value in self.cache.items(): for id, value in self.cache.items():
@ -278,71 +47,67 @@ class ActorController(ActorHttp, CRUDController):
print("NOT FOUND") print("NOT FOUND")
self.logger.error("Actor type '%s' not found (Available Actor Types: %s)" % (actor.type, ', '.join(self.types.keys()))) self.logger.error("Actor type '%s' not found (Available Actor Types: %s)" % (actor.type, ', '.join(self.types.keys())))
async def _stop_actor(self, actor): async def _stop_actor(self, actor):
actor.instance.stop() actor.instance.stop()
await self.cbpi.bus.fire(topic="actor/%s/stopped" % actor.id, id=actor.id) await self.cbpi.bus.fire(topic="actor/%s/stopped" % actor.id, id=actor.id)
@on_event(topic="actor/+/switch/on") @on_event(topic="actor/+/switch/on")
async def on(self, id , future: Future, power=100, **kwargs) -> None: async def on(self, actor_id, future: Future, power=100, **kwargs) -> None:
''' """
Method to switch an actor on. Method to switch an actor on.
Supporting Event Topic "actor/+/on" Supporting Event Topic "actor/+/on"
:param actor_id: the actor id :param actor_id: the actor id
:param future
:param power: as integer value between 1 and 100 :param power: as integer value between 1 and 100
:param kwargs: :param kwargs:
:return: :return:
''' """
id = int(id) actor_id = int(actor_id)
if id in self.cache: if actor_id in self.cache:
self.logger.debug("ON %s" % id) self.logger.debug("ON %s" % actor_id)
actor = self.cache[id].instance actor = self.cache[actor_id].instance
await self.cbpi.bus.fire("actor/%s/on/ok" % id) await self.cbpi.bus.fire("actor/%s/on/ok" % actor_id)
actor.on(power) actor.on(power)
future.set_result("OK") future.set_result("OK")
@on_event(topic="actor/+/toggle") @on_event(topic="actor/+/toggle")
async def toggle(self, id, power=100, **kwargs) -> None: async def toggle(self, actor_id, power=100, **kwargs) -> None:
''' """
Method to toggle an actor on or off Method to toggle an actor on or off
Supporting Event Topic "actor/+/toggle" Supporting Event Topic "actor/+/toggle"
:param id: the actor id
:param power: the power as interger between 0 and 100
:return:
'''
self.logger.debug("TOGGLE %s" % id) :param actor_id: the actor actor_id
id = int(id) :param power: the power as integer between 0 and 100
if id in self.cache: :return:
actor = self.cache[id].instance """
self.logger.debug("TOGGLE %s" % actor_id)
actor_id = int(actor_id)
if actor_id in self.cache:
actor = self.cache[actor_id].instance
if actor.state is True: if actor.state is True:
actor.off() actor.off()
else: else:
actor.on() actor.on()
@on_event(topic="actor/+/off") @on_event(topic="actor/+/off")
async def off(self, id, **kwargs) -> None: async def off(self, actor_id, **kwargs) -> None:
""" """
Method to switch and actor off Method to switch and actor off
Supporting Event Topic "actor/+/off" Supporting Event Topic "actor/+/off"
:param id: the actor id :param actor_id: the actor actor_id
:param kwargs: :param kwargs:
""" """
self.logger.debug("OFF %s" % id) self.logger.debug("OFF %s" % actor_id)
id = int(id) actor_id = int(actor_id)
if id in self.cache: if actor_id in self.cache:
actor = self.cache[id].instance actor = self.cache[actor_id].instance
actor.off() actor.off()
async def _post_add_callback(self, m): async def _post_add_callback(self, m):
@ -355,14 +120,12 @@ class ActorController(ActorHttp, CRUDController):
pass pass
async def _pre_delete_callback(self, actor_id): async def _pre_delete_callback(self, actor_id):
if int(actor_id) not in self.cache: #if int(actor_id) not in self.cache:
return # return
if self.cache[int(actor_id)].instance is not None: if self.cache[int(actor_id)].instance is not None:
await self._stop_actor(self.cache[int(actor_id)]) await self._stop_actor(self.cache[int(actor_id)])
async def _pre_update_callback(self, actor): async def _pre_update_callback(self, actor):
if actor.instance is not None: if actor.instance is not None:
await self._stop_actor(actor) await self._stop_actor(actor)

View file

@ -1,77 +1,13 @@
import logging import logging
import os import os
from aiohttp import web
from cbpi_api import request_mapping
from cbpi_api.exceptions import CBPiException
from core.controller.crud_controller import CRUDController
from core.database.model import ConfigModel
from utils import load_config, json_dumps
from cbpi_api.config import ConfigType from cbpi_api.config import ConfigType
class ConfigHTTPController(): from core.database.model import ConfigModel
@request_mapping(path="/{name}/", method="POST", auth_required=False) from utils import load_config
async def http_post(self, request) -> web.Response:
"""
---
description: Set config parameter
tags:
- Config
parameters:
- name: "name"
in: "path"
description: "Parameter name"
required: true
type: "string"
responses:
"204":
description: successful operation
"""
name = request.match_info['name']
data = await request.json()
print(data)
await self.set(name=name, value=data.get("value"))
return web.Response(status=204)
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request) -> web.Response:
"""
---
description: Get all config parameters
tags:
- Config
responses:
"200":
description: successful operation
"""
return web.json_response(self.cache, dumps=json_dumps)
@request_mapping(path="/{name}/", auth_required=False)
async def http_paramter(self, request) -> web.Response:
"""
---
description: Get all config parameters
tags:
- Config
parameters:
- name: "name"
in: "path"
description: "Parameter name"
required: true
type: "string"
responses:
"200":
description: successful operation
"""
name = request.match_info['name']
if name not in self.cache:
raise CBPiException("Parameter %s not found" % name)
return web.json_response(self.cache.get(name), dumps=json_dumps)
class ConfigController(ConfigHTTPController):
class ConfigController():
''' '''
The main actor controller The main actor controller
''' '''
@ -81,7 +17,7 @@ class ConfigController(ConfigHTTPController):
self.cache = {} self.cache = {}
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
self.cbpi = cbpi self.cbpi = cbpi
self.cbpi.register(self, "/config") self.cbpi.register(self)
async def init(self): async def init(self):
this_directory = os.path.dirname(__file__) this_directory = os.path.dirname(__file__)
@ -90,9 +26,8 @@ class ConfigController(ConfigHTTPController):
for key, value in items.items(): for key, value in items.items():
self.cache[value.name] = value self.cache[value.name] = value
def get(self, name, default=None): def get(self, name, default=None):
self.logger.info("GET CONFIG VALUE %s (default %s)" % (name,default)) self.logger.info("GET CONFIG VALUE %s (default %s)" % (name, default))
if name in self.cache and self.cache[name].value is not None: if name in self.cache and self.cache[name].value is not None:
return self.cache[name].value return self.cache[name].value
else: else:
@ -101,12 +36,10 @@ class ConfigController(ConfigHTTPController):
async def set(self, name, value): async def set(self, name, value):
self.logger.debug("SET %s = %s" % (name, value)) self.logger.debug("SET %s = %s" % (name, value))
if name in self.cache: if name in self.cache:
self.cache[name].value = value self.cache[name].value = value
m = await self.model.update(**self.cache[name].__dict__) await self.model.update(**self.cache[name].__dict__)
await self.cbpi.bus.fire(topic="config/%s/update" % name, name=name, value=value) await self.cbpi.bus.fire(topic="config/%s/update" % name, name=name, value=value)
async def add(self, name, value, type: ConfigType, description, options=None): async def add(self, name, value, type: ConfigType, description, options=None):
m = await self.model.insert(name=name, value=value, type=type.value, description=description, options=options) await self.model.insert(name=name, value=value, type=type.value, description=description, options=options)
await self.cbpi.bus.fire(topic="config/%s/add" % name, name=name, value=value) await self.cbpi.bus.fire(topic="config/%s/add" % name, name=name, value=value)

View file

@ -1,12 +1,15 @@
import pprint import pprint
from abc import ABCMeta from abc import ABCMeta
from cbpi_api.exceptions import CBPiException
class CRUDController(metaclass=ABCMeta): class CRUDController(metaclass=ABCMeta):
cache = {} cache = {}
caching = True caching = True
name = None
def __init__(self, cbpi): def __init__(self, cbpi):
self.cbpi = cbpi self.cbpi = cbpi
@ -17,6 +20,7 @@ class CRUDController(metaclass=ABCMeta):
:return: :return:
''' '''
if self.caching is True: if self.caching is True:
self.cache = await self.model.get_all() self.cache = await self.model.get_all()
@ -37,6 +41,8 @@ class CRUDController(metaclass=ABCMeta):
:param id: :param id:
:return: :return:
''' '''
if id not in self.cache:
raise CBPiException("%s with id %s not found" % (self.name,id))
return self.cache.get(id) return self.cache.get(id)
async def _pre_add_callback(self, data): async def _pre_add_callback(self, data):
@ -61,8 +67,13 @@ class CRUDController(metaclass=ABCMeta):
:param data: :param data:
:return: :return:
''' '''
await self._pre_add_callback(data) await self._pre_add_callback(data)
print("INSSERT ADD", data)
m = await self.model.insert(**data) m = await self.model.insert(**data)
self.cache[m.id] = m self.cache[m.id] = m
await self._post_add_callback(m) await self._post_add_callback(m)
@ -83,7 +94,14 @@ class CRUDController(metaclass=ABCMeta):
:param data: :param data:
:return: :return:
''' '''
id = int(id) id = int(id)
if id not in self.cache:
raise CBPiException("%s with id %s not found" % (self.name,id))
data["id"] = id data["id"] = id
try: try:
@ -121,19 +139,16 @@ class CRUDController(metaclass=ABCMeta):
pass pass
async def delete(self, id): async def delete(self, id):
''' '''
:param id: :param id:
:return: :return:
''' '''
await self._pre_delete_callback(id)
if id not in self.cache: if id not in self.cache:
raise CBPiException("%s with id %s not found" % (self.name,id))
return await self._pre_delete_callback(id)
m = await self.model.delete(id) m = await self.model.delete(id)
await self._post_delete_callback(id) await self._post_delete_callback(id)
try: try:

View file

@ -0,0 +1,30 @@
import logging
from voluptuous import Schema, MultipleInvalid
from core.controller.crud_controller import CRUDController
from core.database.model import DashboardModel, DashboardContentModel
class DashboardController(CRUDController):
model = DashboardModel
name = "Dashboard"
def __init__(self, cbpi):
super(DashboardController, self).__init__(cbpi)
self.cbpi = cbpi
self.logger = logging.getLogger(__name__)
self.cbpi.register(self)
async def get_content(self, dashboard_id):
return await DashboardContentModel.get_by_dashboard_id(dashboard_id)
async def add_content(self, data):
return await DashboardContentModel.insert(**data)
async def delete_content(self, content_id):
await DashboardContentModel.delete(content_id)
async def move_content(self,content_id, x, y):
await DashboardContentModel.update_coordinates(content_id, x, y)

View file

@ -1,9 +1,6 @@
import asyncio import asyncio
import logging import logging
from aiohttp import web
from cbpi_api import request_mapping
from job.aiohttp import setup, get_scheduler_from_app from job.aiohttp import setup, get_scheduler_from_app
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)

View file

@ -1,56 +1,16 @@
import re import re
from aiohttp import web
from cbpi_api import * from cbpi_api import *
from cbpi_api.exceptions import KettleException, ActorException, SensorException from cbpi_api.exceptions import KettleException, ActorException, SensorException
from core.controller.crud_controller import CRUDController from core.controller.crud_controller import CRUDController
from core.database.model import KettleModel from core.database.model import KettleModel
from core.http_endpoints.http_api import HttpAPI
from core.job.aiohttp import get_scheduler_from_app from core.job.aiohttp import get_scheduler_from_app
class KettleHttp(HttpAPI): class KettleController(CRUDController):
@request_mapping(path="/{id:\d+}/automatic", auth_required=False)
async def http_automatic(self, request):
await self.cbpi.kettle.toggle_automtic(int(request.match_info['id']))
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/heater/on", auth_required=False)
async def http_heater_on(self, request):
await self.cbpi.kettle.heater_on(int(request.match_info['id']))
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/heater/off", auth_required=False)
async def http_heater_off(self, request):
await self.cbpi.kettle.heater_off(int(request.match_info['id']))
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/agitator/on", auth_required=False)
async def http_agitator_on(self, request):
await self.cbpi.kettle.agitator_on(int(request.match_info['id']))
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/agitator/off", auth_required=False)
async def http_agitator_off(self, request):
await self.cbpi.kettle.agitator_off(int(request.match_info['id']))
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/targettemp", auth_required=False)
async def http_taget_temp(self, request):
kettle_id = int(request.match_info['id'])
temp = await self.cbpi.kettle.get_traget_temp(kettle_id)
return web.json_response(data=dict(target_temp=temp, kettle_id=kettle_id))
@request_mapping(path="/{id:\d+}/temp", auth_required=False)
async def http_temp(self, request):
kettle_id = int(request.match_info['id'])
temp = await self.cbpi.kettle.get_temp(kettle_id)
return web.json_response(data=dict(temp=temp, kettle_id=kettle_id))
class KettleController(CRUDController, KettleHttp):
''' '''
The main kettle controller The main kettle controller
''' '''
@ -60,7 +20,7 @@ class KettleController(CRUDController, KettleHttp):
super(KettleController, self).__init__(cbpi) super(KettleController, self).__init__(cbpi)
self.cbpi = cbpi self.cbpi = cbpi
self.types = {} self.types = {}
self.cbpi.register(self, "/kettle") self.cbpi.register(self)
async def init(self): async def init(self):
''' '''
@ -142,8 +102,8 @@ class KettleController(CRUDController, KettleHttp):
raise KettleException("Kettle not found") raise KettleException("Kettle not found")
if kettle.sensor is None: if kettle.sensor is None:
raise ActorException("Actor not defined for kettle id %s" % id) raise ActorException("Actor not defined for kettle id %s" % id)
id = kettle.heater heater_id = kettle.heater
await self.cbpi.bus.fire(topic="actor/%s/switch/on" % id, id=id, power=99) await self.cbpi.bus.fire(topic="actor/%s/switch/on" % heater_id, actor_id=heater_id, power=99)
async def heater_off(self, id): async def heater_off(self, id):
''' '''
@ -158,8 +118,8 @@ class KettleController(CRUDController, KettleHttp):
raise KettleException("Kettle not found") raise KettleException("Kettle not found")
if kettle.sensor is None: if kettle.sensor is None:
raise ActorException("Actor not defined for kettle id %s" % id) raise ActorException("Actor not defined for kettle id %s" % id)
id = kettle.heater heater_id = kettle.heater
await self.cbpi.bus.fire(topic="actor/%s/switch/off" % id, id=id, power=99) await self.cbpi.bus.fire(topic="actor/%s/switch/off" % heater_id, actor_id=heater_id, power=99)
async def agitator_on(self, id): async def agitator_on(self, id):
kettle = await self.get_one(id) kettle = await self.get_one(id)
@ -168,7 +128,7 @@ class KettleController(CRUDController, KettleHttp):
if kettle.sensor is None: if kettle.sensor is None:
raise ActorException("Actor not defined for kettle id %s" % id) raise ActorException("Actor not defined for kettle id %s" % id)
agitator_id = kettle.agitator agitator_id = kettle.agitator
await self.cbpi.bus.fire(topic="actor/%s/switch/on" % agitator_id, id=agitator_id, power=99) await self.cbpi.bus.fire(topic="actor/%s/switch/on" % agitator_id, actor_id=agitator_id, power=99)
async def agitator_off(self, id): async def agitator_off(self, id):
kettle = await self.get_one(id) kettle = await self.get_one(id)
@ -177,7 +137,7 @@ class KettleController(CRUDController, KettleHttp):
if kettle.sensor is None: if kettle.sensor is None:
raise ActorException("Actor not defined for kettle id %s" % id) raise ActorException("Actor not defined for kettle id %s" % id)
agitator_id = kettle.agitator agitator_id = kettle.agitator
await self.cbpi.bus.fire(topic="actor/%s/switch/off" % agitator_id, id=agitator_id, power=99) await self.cbpi.bus.fire(topic="actor/%s/switch/off" % agitator_id, actor_id=agitator_id, power=99)
async def get_traget_temp(self, id): async def get_traget_temp(self, id):
kettle = await self.get_one(id) kettle = await self.get_one(id)

View file

@ -1,6 +1,7 @@
from cbpi_api import * from cbpi_api import *
class NotificationController():
class NotificationController(object):
''' '''
This the notification controller This the notification controller
''' '''
@ -17,4 +18,4 @@ class NotificationController():
@on_event(topic="notification/#") @on_event(topic="notification/#")
async def _on_event(self, key, message, type, **kwargs): async def _on_event(self, key, message, type, **kwargs):
self.cbpi.ws.send("YES") self.cbpi.ws.send("YES")

View file

@ -5,161 +5,30 @@ from cbpi_api import request_mapping
from core.controller.crud_controller import CRUDController from core.controller.crud_controller import CRUDController
from core.database.model import SensorModel from core.database.model import SensorModel
from core.http_endpoints.http_api import HttpAPI
from core.job.aiohttp import get_scheduler_from_app from core.job.aiohttp import get_scheduler_from_app
from core.utils.encoder import ComplexEncoder from core.utils.encoder import ComplexEncoder
class SensorController(CRUDController, HttpAPI): class SensorController(CRUDController):
model = SensorModel model = SensorModel
def __init__(self, cbpi): def __init__(self, cbpi):
self.cbpi = cbpi self.cbpi = cbpi
self.cbpi.register(self, "/sensor") self.cbpi.register(self)
self.service = self self.service = self
self.types = {} self.types = {}
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
self.sensors = {} self.sensors = {}
def info(self):
return json.dumps(dict(name="SensorController", types=self.types), cls=ComplexEncoder)
@request_mapping(path="/types", auth_required=False)
async def get_types(self, request):
"""
---
description: Get all sensor types
tags:
- Sensor
responses:
"200":
description: successful operation
"""
return await super().get_types(request)
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request):
"""
---
description: Get all sensor
tags:
- Sensor
responses:
"204":
description: successful operation
"""
return await super().http_get_all(request)
@request_mapping(path="/{id:\d+}", auth_required=False)
async def http_get_one(self, request):
"""
---
description: Get an sensor
tags:
- Sensor
parameters:
- name: "id"
in: "path"
description: "Sensor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
return await super().http_get_one(request)
@request_mapping(path="/", method="POST", auth_required=False)
async def http_add(self, request):
"""
---
description: Get one sensor
tags:
- Sensor
parameters:
- in: body
name: body
description: Created an sensor
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
type: object
responses:
"204":
description: successful operation
"""
return await super().http_add(request)
@request_mapping(path="/{id}", method="PUT", auth_required=False)
async def http_update(self, request):
"""
---
description: Update an sensor
tags:
- Sensor
parameters:
- name: "id"
in: "path"
description: "Sensor ID"
required: true
type: "integer"
format: "int64"
- in: body
name: body
description: Update an sensor
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
type: object
responses:
"200":
description: successful operation
"""
return await super().http_update(request)
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
async def http_delete_one(self, request):
"""
---
description: Delete an sensor
tags:
- Sensor
parameters:
- name: "id"
in: "path"
description: "Sensor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
return await super().http_delete_one(request)
async def init(self): async def init(self):
''' '''
This method initializes all actors during startup. It creates actor instances This method initializes all actors during startup. It creates actor instances
:return: :return:
''' '''
await super(SensorController, self).init() await super(SensorController, self).init()
for id, value in self.cache.items(): for id, value in self.cache.items():
await self.init_sensor(value) await self.init_sensor(value)
@ -198,7 +67,6 @@ class SensorController(CRUDController, HttpAPI):
async def _pre_delete_callback(self, sensor_id): async def _pre_delete_callback(self, sensor_id):
if int(sensor_id) not in self.cache: if int(sensor_id) not in self.cache:
return return
if self.cache[int(sensor_id)].instance is not None: if self.cache[int(sensor_id)].instance is not None:
await self.stop_sensor(self.cache[int(sensor_id)]) await self.stop_sensor(self.cache[int(sensor_id)])

View file

@ -1,233 +1,13 @@
import asyncio import asyncio
import time import time
from aiohttp import web
from cbpi_api import * from cbpi_api import *
from cbpi_api.exceptions import CBPiException
from core.controller.crud_controller import CRUDController from core.controller.crud_controller import CRUDController
from core.database.model import StepModel from core.database.model import StepModel
from core.http_endpoints.http_api import HttpAPI
class StepHttpAPI(HttpAPI): class StepController(CRUDController):
@request_mapping(path="/types", auth_required=False)
async def get_types(self, request):
"""
---
description: Get all step types
tags:
- Step
responses:
"200":
description: successful operation
"""
return await super().get_types(request)
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request):
"""
---
description: Switch step on
tags:
- Step
parameters:
- name: "id"
in: "path"
description: "step ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
return await super().http_get_all(request)
@request_mapping(path="/{id:\d+}", auth_required=False)
async def http_get_one(self, request):
"""
---
description: Get one step
tags:
- Step
parameters:
- name: "id"
in: "path"
description: "step ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
return await super().http_get_one(request)
@request_mapping(path="/", method="POST", auth_required=False)
async def http_add(self, request):
"""
---
description: Get one step
tags:
- Step
parameters:
- in: body
name: body
description: Created an step
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
type: object
responses:
"204":
description: successful operation
"""
return await super().http_add(request)
@request_mapping(path="/{id}", method="PUT", auth_required=False)
async def http_update(self, request):
"""
---
description: Update an step
tags:
- Step
parameters:
- name: "id"
in: "path"
description: "step ID"
required: true
type: "integer"
format: "int64"
- in: body
name: body
description: Update an step
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
type: object
responses:
"200":
description: successful operation
"""
return await super().http_update(request)
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
async def http_delete_one(self, request):
"""
---
description: Delete a step
tags:
- Step
parameters:
- name: "id"
in: "path"
description: "Step ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
return await super().http_delete_one(request)
@request_mapping(path="/action", auth_required=False)
async def http_action(self, request):
"""
---
description: Call step action
tags:
- Step
responses:
"204":
description: successful operation
"""
await self.cbpi.bus.fire("step/action", action="test")
return web.Response(text="OK")
@request_mapping(path="/start", auth_required=False)
async def http_start(self, request):
"""
---
description: Start Brewing Process
tags:
- Step
responses:
"204":
description: successful operation
"""
if self.is_running():
raise CBPiException("Brewing Process Already Running")
result = await self.cbpi.bus.fire("step/start")
r = result.get("core.controller.step_controller.handle_start")
if r[0] is True:
return web.Response(status=204)
else:
raise CBPiException("Failed to start brewing process")
@request_mapping(path="/reset", auth_required=False)
async def http_reset(self, request):
"""
---
description: Reset Brewing Process
tags:
- Step
responses:
"204":
description: successful operation
"""
await self.cbpi.bus.fire("step/reset")
return web.Response(text="OK")
@request_mapping(path="/next", auth_required=False)
async def http_next(self, request):
"""
---
description: Start next step
tags:
- Step
responses:
"204":
description: successful operation
"""
await self.cbpi.bus.fire("step/next")
return web.Response(text="OK")
@request_mapping(path="/stop", auth_required=False)
async def http_stop(self, request):
"""
---
description: Stop next step
tags:
- Step
responses:
"204":
description: successful operation
"""
await self.cbpi.bus.fire("step/stop")
return web.Response(text="OK")
class StepController(StepHttpAPI, CRUDController):
''' '''
The Step Controller. This controller is responsible to start and stop the brewing steps. The Step Controller. This controller is responsible to start and stop the brewing steps.
@ -243,7 +23,7 @@ class StepController(StepHttpAPI, CRUDController):
self.types = {} self.types = {}
self.current_step = None self.current_step = None
self.current_job = None self.current_job = None
self.cbpi.register(self, "/step") self.cbpi.register(self)
async def init(self): async def init(self):

View file

@ -28,11 +28,9 @@ class SystemController():
result = [] result = []
for j in scheduler: for j in scheduler:
try: try:
result.append(dict(name=j.name, type=j.type, time=j.start_time)) result.append(dict(name=j.name, type=j.type, time=j.start_time))
except: except:
pass pass
# await j.close()
return web.json_response(data=result) return web.json_response(data=result)
@request_mapping("/events", method="GET", name="get_all_events", auth_required=False) @request_mapping("/events", method="GET", name="get_all_events", auth_required=False)

View file

@ -8,9 +8,10 @@ from aiohttp_session import session_middleware
from aiohttp_session.cookie_storage import EncryptedCookieStorage from aiohttp_session.cookie_storage import EncryptedCookieStorage
from aiohttp_swagger import setup_swagger from aiohttp_swagger import setup_swagger
from cbpi_api.exceptions import CBPiException from cbpi_api.exceptions import CBPiException
from voluptuous import MultipleInvalid
from controller.dashboard_controller import DashboardController
from controller.job_controller import JobController from controller.job_controller import JobController
from core.websocket import CBPiWebSocket
from core.controller.actor_controller import ActorController from core.controller.actor_controller import ActorController
from core.controller.config_controller import ConfigController from core.controller.config_controller import ConfigController
from core.controller.kettle_controller import KettleController from core.controller.kettle_controller import KettleController
@ -23,6 +24,13 @@ from core.database.model import DBModel
from core.eventbus import CBPiEventBus from core.eventbus import CBPiEventBus
from core.http_endpoints.http_login import Login from core.http_endpoints.http_login import Login
from core.utils import * from core.utils import *
from core.websocket import CBPiWebSocket
from http_endpoints.http_actor import ActorHttpEndpoints
from http_endpoints.http_config import ConfigHttpEndpoints
from http_endpoints.http_dashboard import DashBoardHttpEndpoints
from http_endpoints.http_kettle import KettleHttpEndpoints
from http_endpoints.http_sensor import SensorHttpEndpoints
from http_endpoints.http_step import StepHttpEndpoints
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
@ -43,6 +51,8 @@ async def error_middleware(request, handler):
except CBPiException as ex: except CBPiException as ex:
message = str(ex) message = str(ex)
return web.json_response(status=500, data={'error': message}) return web.json_response(status=500, data={'error': message})
except MultipleInvalid as ex:
return web.json_response(status=500, data={'error': str(ex)})
return web.json_response({'error': message}) return web.json_response({'error': message})
class CraftBeerPi(): class CraftBeerPi():
@ -69,6 +79,15 @@ class CraftBeerPi():
self.config = ConfigController(self) self.config = ConfigController(self)
self.kettle = KettleController(self) self.kettle = KettleController(self)
self.step = StepController(self) self.step = StepController(self)
self.dashboard = DashboardController(self)
self.http_step = StepHttpEndpoints(self)
self.http_sensor = SensorHttpEndpoints(self)
self.http_config = ConfigHttpEndpoints(self)
self.http_actor = ActorHttpEndpoints(self)
self.http_kettle = KettleHttpEndpoints(self)
self.http_dashboard = DashBoardHttpEndpoints(self)
self.notification = NotificationController(self) self.notification = NotificationController(self)
self.login = Login(self) self.login = Login(self)
@ -103,7 +122,11 @@ class CraftBeerPi():
self.register_on_startup(obj) self.register_on_startup(obj)
def register_http_endpoints(self, obj, url_prefix=None, static=None): def register_http_endpoints(self, obj, url_prefix=None, static=None):
if url_prefix is None:
logger.debug("URL Prefix is None for %s. No endpoints will be registered. Please set / explicit if you want to add it to the root path" % obj)
return
routes = [] routes = []
for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "route")]: for method in [getattr(obj, f) for f in dir(obj) if callable(getattr(obj, f)) and hasattr(getattr(obj, f), "route")]:
http_method = method.__getattribute__("method") http_method = method.__getattribute__("method")
@ -131,7 +154,7 @@ class CraftBeerPi():
} }
switcher[http_method]() switcher[http_method]()
if url_prefix is not None: if url_prefix != "/":
logger.debug("URL Prefix: %s " % (url_prefix,)) logger.debug("URL Prefix: %s " % (url_prefix,))
sub = web.Application() sub = web.Application()
sub.add_routes(routes) sub.add_routes(routes)
@ -206,6 +229,7 @@ class CraftBeerPi():
await self.actor.init() await self.actor.init()
await self.kettle.init() await self.kettle.init()
await self.call_initializer(self.app) await self.call_initializer(self.app)
await self.dashboard.init()
self._swagger_setup() self._swagger_setup()
return self.app return self.app

View file

@ -1,18 +1,38 @@
import json import json
import aiosqlite import aiosqlite
from cbpi_api.exceptions import CBPiException
from voluptuous import Schema, MultipleInvalid
from core.database.orm_framework import DBModel from core.database.orm_framework import DBModel
DATABASE_FILE = "./craftbeerpi.db" DATABASE_FILE = "./craftbeerpi.db"
class ActorModel(DBModel): class ActorModel(DBModel):
__fields__ = ["name", "type", "config"] __fields__ = ["name", "type", "config"]
__table_name__ = "actor" __table_name__ = "actor"
__json_fields__ = ["config"] __json_fields__ = ["config"]
__validation_schema__ = {
'id': int,
'name': str,
'type': str,
'config': dict
}
class SensorModel(DBModel): class SensorModel(DBModel):
__fields__ = ["name", "type", "config"] __fields__ = ["name", "type", "config"]
__table_name__ = "sensor" __table_name__ = "sensor"
__json_fields__ = ["config"] __json_fields__ = ["config"]
__validation_schema__ = {
'id': int,
'name': str,
'type': str,
'config': dict
}
class ConfigModel(DBModel): class ConfigModel(DBModel):
__fields__ = ["type", "value", "description", "options"] __fields__ = ["type", "value", "description", "options"]
@ -20,14 +40,15 @@ class ConfigModel(DBModel):
__json_fields__ = ["options"] __json_fields__ = ["options"]
__priamry_key__ = "name" __priamry_key__ = "name"
class KettleModel(DBModel): class KettleModel(DBModel):
__fields__ = ["name","sensor", "heater", "automatic", "logic", "config", "agitator", "target_temp"] __fields__ = ["name", "sensor", "heater", "automatic", "logic", "config", "agitator", "target_temp"]
__table_name__ = "kettle" __table_name__ = "kettle"
__json_fields__ = ["config"] __json_fields__ = ["config"]
class StepModel(DBModel): class StepModel(DBModel):
__fields__ = ["order", "name", "type", "stepstate", "state", "start", "end", "config", "kettleid"] __fields__ = ["order", "name", "type", "stepstate", "state", "start", "end", "config", "kettleid"]
__table_name__ = "step" __table_name__ = "step"
__json_fields__ = ["config", "stepstate"] __json_fields__ = ["config", "stepstate"]
@ -40,11 +61,10 @@ class StepModel(DBModel):
@classmethod @classmethod
async def get_by_state(cls, state, order=True): async def get_by_state(cls, state, order=True):
async with aiosqlite.connect(DATABASE_FILE) as db: async with aiosqlite.connect(DATABASE_FILE) as db:
db.row_factory = aiosqlite.Row db.row_factory = aiosqlite.Row
db.row_factory = DBModel.dict_factory db.row_factory = DBModel.dict_factory
async with db.execute("SELECT * FROM %s WHERE state = ? ORDER BY %s.'order'" % (cls.__table_name__, cls.__table_name__,), state) as cursor: async with db.execute("SELECT * FROM %s WHERE state = ? ORDER BY %s.'order'" % (cls.__table_name__, cls.__table_name__,), state) as cursor:
row = await cursor.fetchone() row = await cursor.fetchone()
if row is not None: if row is not None:
return cls(row) return cls(row)
@ -54,6 +74,50 @@ class StepModel(DBModel):
@classmethod @classmethod
async def reset_all_steps(cls): async def reset_all_steps(cls):
async with aiosqlite.connect(DATABASE_FILE) as db: async with aiosqlite.connect(DATABASE_FILE) as db:
cursor = await db.execute("UPDATE %s SET state = 'I', stepstate = NULL , start = NULL, end = NULL " % cls.__table_name__) await db.execute("UPDATE %s SET state = 'I', stepstate = NULL , start = NULL, end = NULL " % cls.__table_name__)
await db.commit() await db.commit()
class DashboardModel(DBModel):
__fields__ = ["name"]
__table_name__ = "dashboard"
__json_fields__ = []
class DashboardContentModel(DBModel):
__fields__ = ["dbid", "type", "element_id", "x", "y","config"]
__table_name__ = "dashboard_content"
__json_fields__ = ["config"]
__validation_schema__ = {
'dbid': int,
'element_id': int,
'type': str,
'x': int,
'y': int,
'config': dict
}
@classmethod
async def get_by_dashboard_id(cls, id, as_array=False):
result = []
async with aiosqlite.connect(DATABASE_FILE) as db:
db.row_factory = DBModel.dict_factory
async with db.execute("SELECT * FROM %s WHERE dbid = ?" % (cls.__table_name__), (id,)) as cursor:
async for row in cursor:
result.append(cls(row))
await cursor.close()
return result
@classmethod
async def update_coordinates(cls, id, x, y):
async with aiosqlite.connect(DATABASE_FILE) as db:
await db.execute("UPDATE %s SET x = ?, y = ? WHERE id = ?" % (cls.__table_name__), (x, y, id,))
await db.commit()
@classmethod
async def delete_by_dashboard_id(cls, id):
async with aiosqlite.connect(DATABASE_FILE) as db:
await db.execute("DELETE FROM %s WHERE dbid = ?" % (cls.__table_name__), (id,))
await db.commit()

View file

@ -2,6 +2,9 @@ import json
import aiosqlite import aiosqlite
import os import os
from cbpi_api.exceptions import CBPiException
from voluptuous import MultipleInvalid, Schema
DATABASE_FILE = "./craftbeerpi.db" DATABASE_FILE = "./craftbeerpi.db"
@ -10,6 +13,7 @@ class DBModel(object):
__as_array__ = False __as_array__ = False
__order_by__ = None __order_by__ = None
__json_fields__ = [] __json_fields__ = []
__validation_schema__ = None
def __init__(self, args): def __init__(self, args):
self.__setattr__(self.__priamry_key__, args[self.__priamry_key__]) self.__setattr__(self.__priamry_key__, args[self.__priamry_key__])
@ -37,6 +41,15 @@ class DBModel(object):
qry = open(os.path.join(this_directory, '../../config/create_database.sql'), 'r').read() qry = open(os.path.join(this_directory, '../../config/create_database.sql'), 'r').read()
cursor = await db.executescript(qry) cursor = await db.executescript(qry)
@classmethod
def validate(cls, data):
if cls.__validation_schema__ is not None:
try:
schema = Schema(cls.__validation_schema__)
schema(data)
except MultipleInvalid as e:
raise CBPiException(str(e))
@classmethod @classmethod
async def get_all(cls): async def get_all(cls):
@ -85,6 +98,9 @@ class DBModel(object):
@classmethod @classmethod
async def insert(cls, **kwargs): async def insert(cls, **kwargs):
cls.validate(kwargs)
async with aiosqlite.connect(DATABASE_FILE) as db: async with aiosqlite.connect(DATABASE_FILE) as db:
if cls.__priamry_key__ is not None and cls.__priamry_key__ in kwargs: if cls.__priamry_key__ is not None and cls.__priamry_key__ in kwargs:
query = "INSERT INTO %s (%s, %s) VALUES (?, %s)" % ( query = "INSERT INTO %s (%s, %s) VALUES (?, %s)" % (

View file

@ -124,9 +124,7 @@ class CBPiEventBus(object):
if inspect.iscoroutinefunction(content_obj.method): if inspect.iscoroutinefunction(content_obj.method):
if content_obj.supports_future is True: if content_obj.supports_future is True:
fut = self.loop.create_future() fut = self.loop.create_future()
futures["%s.%s" % (content_obj.method.__module__, content_obj.name)] = fut futures["%s.%s" % (content_obj.method.__module__, content_obj.name)] = fut
self.loop.create_task(content_obj.method(**kwargs, topic = topic, future=fut)) self.loop.create_task(content_obj.method(**kwargs, topic = topic, future=fut))

View file

@ -7,6 +7,9 @@ class CustomActor(CBPiActor):
# Custom property which can be configured by the user # Custom property which can be configured by the user
gpio = Property.Number(label="Test") gpio = Property.Number(label="Test")
v1 = Property.Text(label="Test")
v2 = Property.Kettle(label="Test")
v3 = Property.Sensor(label="Test")
def init(self): def init(self):
pass pass

View file

@ -0,0 +1,234 @@
from aiohttp import web
from cbpi_api import request_mapping
from cbpi_api.exceptions import CBPiException
from http_endpoints.http_curd_endpoints import HttpCrudEndpoints
auth = False
class ActorHttpEndpoints(HttpCrudEndpoints):
def __init__(self, cbpi):
super().__init__(cbpi)
self.controller = cbpi.actor
self.cbpi.register(self, "/actor")
@request_mapping(path="/types", auth_required=False)
async def get_types(self, request):
"""
---
description: Get all actor types
tags:
- Actor
responses:
"200":
description: successful operation
"""
return await super().get_types(request)
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request):
"""
---
description: Switch actor on
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
return await super().http_get_all(request)
@request_mapping(path="/{id:\d+}", auth_required=False)
async def http_get_one(self, request):
"""
---
description: Get one Actor
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
return await super().http_get_one(request)
@request_mapping(path="/", method="POST", auth_required=False)
async def http_add(self, request):
"""
---
description: Get one Actor
tags:
- Actor
parameters:
- in: body
name: body
description: Created an actor
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
type: object
responses:
"204":
description: successful operation
"""
return await super().http_add(request)
@request_mapping(path="/{id}", method="PUT", auth_required=False)
async def http_update(self, request):
"""
---
description: Update an actor
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
- in: body
name: body
description: Update an actor
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
type: object
responses:
"200":
description: successful operation
"""
return await super().http_update(request)
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
async def http_delete_one(self, request):
"""
---
description: Delete an actor
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
return await super().http_delete_one(request)
@request_mapping(path="/{id:\d+}/on", method="POST", auth_required=auth)
async def http_on(self, request) -> web.Response:
"""
---
description: Switch actor on
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
actor_id = int(request.match_info['id'])
result = await self.cbpi.bus.fire(topic="actor/%s/switch/on" % actor_id, actor_id=actor_id, power=99)
for key, value in result.results.items():
pass
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/off", method="POST", auth_required=auth)
async def http_off(self, request) -> web.Response:
"""
---
description: Switch actor off
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
actor_id = int(request.match_info['id'])
await self.cbpi.bus.fire(topic="actor/%s/off" % actor_id, actor_id=actor_id)
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/toggle", method="POST", auth_required=auth)
async def http_toggle(self, request) -> web.Response:
"""
---
description: Toogle an actor on or off
tags:
- Actor
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
actor_id = int(request.match_info['id'])
await self.cbpi.bus.fire(topic="actor/%s/toggle" % actor_id, actor_id=actor_id)
return web.Response(status=204)

View file

@ -0,0 +1,72 @@
from aiohttp import web
from cbpi_api import request_mapping
from cbpi_api.exceptions import CBPiException
from http_endpoints.http_curd_endpoints import HttpCrudEndpoints
from utils import json_dumps
class ConfigHttpEndpoints(HttpCrudEndpoints):
def __init__(self, cbpi):
super().__init__(cbpi)
self.controller = cbpi.config
self.cbpi.register(self, "/config")
@request_mapping(path="/{name}/", method="POST", auth_required=False)
async def http_post(self, request) -> web.Response:
"""
---
description: Set config parameter
tags:
- Config
parameters:
- name: "name"
in: "path"
description: "Parameter name"
required: true
type: "string"
responses:
"204":
description: successful operation
"""
name = request.match_info['name']
data = await request.json()
await self.controller.set(name=name, value=data.get("value"))
return web.Response(status=204)
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request) -> web.Response:
"""
---
description: Get all config parameters
tags:
- Config
responses:
"200":
description: successful operation
"""
return web.json_response(self.controller.cache, dumps=json_dumps)
@request_mapping(path="/{name}/", auth_required=False)
async def http_paramter(self, request) -> web.Response:
"""
---
description: Get all config parameters
tags:
- Config
parameters:
- name: "name"
in: "path"
description: "Parameter name"
required: true
type: "string"
responses:
"200":
description: successful operation
"""
name = request.match_info['name']
if name not in self.cache:
raise CBPiException("Parameter %s not found" % name)
return web.json_response(self.cache.get(name), dumps=json_dumps)

View file

@ -1,45 +1,51 @@
import logging import logging
from aiohttp import web from aiohttp import web
from aiohttp_swagger import swagger_path
from cbpi_api import * from cbpi_api import *
from core.utils.utils import json_dumps from core.utils.utils import json_dumps
class HttpAPI():
class HttpCrudEndpoints():
def __init__(self, cbpi): def __init__(self, cbpi):
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
self.cbpi = cbpi self.cbpi = cbpi
@request_mapping(path="/types", auth_required=False) @request_mapping(path="/types", auth_required=False)
async def get_types(self, request): async def get_types(self, request):
if self.types is not None: if self.controller.types is not None:
return web.json_response(data=self.types, dumps=json_dumps) return web.json_response(data=self.controller.types, dumps=json_dumps)
else: else:
return web.Response(status=404, text="Types not supported by endpoint") return web.Response(status=404, text="Types not supported by endpoint")
@request_mapping(path="/", auth_required=False) @request_mapping(path="/", auth_required=False)
async def http_get_all(self, request): async def http_get_all(self, request):
return web.json_response(await self.get_all(force_db_update=True), dumps=json_dumps) return web.json_response(await self.controller.get_all(force_db_update=True), dumps=json_dumps)
@request_mapping(path="/{id:\d+}", auth_required=False) @request_mapping(path="/{id:\d+}", auth_required=False)
async def http_get_one(self, request): async def http_get_one(self, request):
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.controller.get_one(id), dumps=json_dumps)
@request_mapping(path="/", method="POST", auth_required=False) @request_mapping(path="/", method="POST", auth_required=False)
async def http_add(self, request): async def http_add(self, request):
data = await request.json() data = await request.json()
obj = await self.add(**data) print(data)
obj = await self.controller.add(**data)
return web.json_response(obj, dumps=json_dumps) return web.json_response(obj, dumps=json_dumps)
@request_mapping(path="/{id}", method="PUT", auth_required=False) @request_mapping(path="/{id}", method="PUT", auth_required=False)
async def http_update(self, request): async def http_update(self, request):
id = request.match_info['id'] id = request.match_info['id']
data = await request.json() data = await request.json()
obj = await self.update(id, data) obj = await self.controller.update(id, data)
return web.json_response(obj, dumps=json_dumps) return web.json_response(obj, dumps=json_dumps)
@request_mapping(path="/{id}", method="DELETE", auth_required=False) @request_mapping(path="/{id}", method="DELETE", auth_required=False)
async def http_delete_one(self, request): async def http_delete_one(self, request):
id = request.match_info['id'] id = request.match_info['id']
await self.delete(int(id)) await self.controller.delete(int(id))
return web.Response(status=204) return web.Response(status=204)

View file

@ -0,0 +1,260 @@
from aiohttp import web
from cbpi_api import request_mapping
from voluptuous import Schema
from database.model import DashboardContentModel
from http_endpoints.http_curd_endpoints import HttpCrudEndpoints
from utils import json_dumps
class DashBoardHttpEndpoints(HttpCrudEndpoints):
def __init__(self, cbpi):
self.cbpi = cbpi
self.controller = cbpi.dashboard
self.cbpi.register(self, "/dashboard")
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request):
"""
---
description: Get all dashboards
tags:
- Dashboard
responses:
"200":
description: successful operation
"""
return await super().http_get_all(request)
@request_mapping(path="/{id:\d+}", auth_required=False)
async def http_get_one(self, request):
"""
---
description: Get one Dashboard by id
tags:
- Dashboard
parameters:
- name: "id"
in: "path"
description: "Actor ID"
required: true
type: "integer"
format: "int64"
responses:
"200":
description: successful operation
"""
return await super().http_get_one(request)
@request_mapping(path="/", method="POST", auth_required=False)
async def http_add(self, request):
"""
---
description: Create a new Dashboard
tags:
- Dashboard
parameters:
- in: body
name: body
description: Create a new Dashboard
required: false
schema:
type: object
properties:
name:
type: string
responses:
"200":
description: successful operation
"""
return await super().http_add(request)
@request_mapping(path="/{id:\d+}", method="PUT", auth_required=False)
async def http_update(self, request):
"""
---
description: Update a Dashboard
tags:
- Dashboard
parameters:
- name: "id"
in: "path"
description: "Dashboard ID"
required: true
type: "integer"
format: "int64"
- in: body
name: body
description: Update a dashboard
required: false
schema:
type: object
properties:
name:
type: string
responses:
"200":
description: successful operation
"""
return await super().http_update(request)
@request_mapping(path="/{id:\d+}", method="DELETE", auth_required=False)
async def http_delete_one(self, request):
"""
---
description: Delete a Dashboard
tags:
- Dashboard
parameters:
- name: "id"
in: "path"
description: "Dashboard ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
return await super().http_delete_one(request)
@request_mapping(path="/{id:\d+}/content", auth_required=False)
async def get_content(self, request):
"""
---
description: Get Dashboard Content
tags:
- Dashboard
parameters:
- name: "id"
in: "path"
description: "Dashboard ID"
required: true
type: "integer"
format: "int64"
responses:
"200":
description: successful operation
"""
dashboard_id = int(request.match_info['id'])
return web.json_response(await self.cbpi.dashboard.get_content(dashboard_id), dumps=json_dumps)
@request_mapping(path="/{id:\d+}/content", method="POST", auth_required=False)
async def add_content(self, request):
"""
---
description: Add Dashboard Content
tags:
- Dashboard
parameters:
- name: "id"
in: "path"
description: "Dashboard ID"
required: true
type: "integer"
format: "int64"
- name: body
in: body
description: Dashboard Content
required: true
schema:
type: object
properties:
element_id:
type: string
type:
type: string
x:
type: "integer"
format: "int64"
y:
type: "integer"
format: "int64"
config:
type: object
responses:
"200":
description: successful operation
"""
data = await request.json()
return web.json_response(await self.cbpi.dashboard.add_content(data), dumps=json_dumps)
@request_mapping(path="/{id:\d+}/content/{content_id:\d+}", method="DELETE", auth_required=False)
async def delete_content(self, request):
"""
---
description: Delete Dashboard Content
tags:
- Dashboard
parameters:
- name: "id"
in: "path"
description: "Dashboard ID"
required: true
type: "integer"
format: "int64"
- name: "content_id"
in: "path"
description: "Dashboard Content ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
content_id = int(request.match_info['content_id'])
await self.cbpi.dashboard.delete_content(content_id)
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/content/{content_id:\d+}/move", method="PUT", auth_required=False)
async def move_content(self,request):
"""
---
description: Get Dashboard Content
tags:
- Dashboard
parameters:
- name: "id"
in: "path"
description: "Dashboard ID"
required: true
type: "integer"
format: "int64"
- name: "content_id"
in: "path"
description: "Content ID"
required: true
type: "integer"
format: "int64"
- name: body
in: body
description: Dashboard Content
required: true
schema:
type: object
properties:
x:
type: "integer"
format: "int64"
y:
type: "integer"
format: "int64"
responses:
"200":
description: successful operation
"""
data = await request.json()
schema = Schema({"x": int, "y": int})
schema(data)
content_id = int(request.match_info['content_id'])
return web.json_response(await self.cbpi.dashboard.move_content(content_id,data["x"], data["y"]), dumps=json_dumps)

View file

@ -0,0 +1,52 @@
from aiohttp import web
from cbpi_api import request_mapping
from http_endpoints.http_curd_endpoints import HttpCrudEndpoints
auth = False
class KettleHttpEndpoints(HttpCrudEndpoints):
def __init__(self, cbpi):
super().__init__(cbpi)
self.controller = cbpi.kettle
self.cbpi.register(self, "/kettle")
@request_mapping(path="/{id:\d+}/automatic", auth_required=False)
async def http_automatic(self, request):
await self.controller.toggle_automtic(int(request.match_info['id']))
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/heater/on", auth_required=False)
async def http_heater_on(self, request):
await self.controller.heater_on(int(request.match_info['id']))
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/heater/off", auth_required=False)
async def http_heater_off(self, request):
await self.controller.heater_off(int(request.match_info['id']))
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/agitator/on", auth_required=False)
async def http_agitator_on(self, request):
await self.controller.agitator_on(int(request.match_info['id']))
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/agitator/off", auth_required=False)
async def http_agitator_off(self, request):
await self.controller.agitator_off(int(request.match_info['id']))
return web.Response(status=204)
@request_mapping(path="/{id:\d+}/targettemp", auth_required=False)
async def http_taget_temp(self, request):
kettle_id = int(request.match_info['id'])
temp = await self.controller.get_traget_temp(kettle_id)
return web.json_response(data=dict(target_temp=temp, kettle_id=kettle_id))
@request_mapping(path="/{id:\d+}/temp", auth_required=False)
async def http_temp(self, request):
kettle_id = int(request.match_info['id'])
temp = await self.controller.get_temp(kettle_id)
return web.json_response(data=dict(temp=temp, kettle_id=kettle_id))

View file

@ -8,7 +8,7 @@ class Login():
def __init__(self,cbpi): def __init__(self,cbpi):
self.cbpi = cbpi self.cbpi = cbpi
self.cbpi.register(self) self.cbpi.register(self, url_prefix="/")
self.db = {cbpi.static_config.get("username", "cbpi"): cbpi.static_config.get("password", "cbpi")} self.db = {cbpi.static_config.get("username", "cbpi"): cbpi.static_config.get("password", "cbpi")}
@ -23,11 +23,8 @@ class Login():
params = await request.post() params = await request.post()
user = params.get('username', None) user = params.get('username', None)
password = params.get('password', None)
print("UUSEr", user, password, str(self.db[user]))
if (user in self.db and
params.get('password', None) == str(self.db[user])):
if (user in self.db and params.get('password', None) == str(self.db[user])):
# User is in our database, remember their login details # User is in our database, remember their login details
await auth.remember(request, user) await auth.remember(request, user)
return web.Response(body='OK'.encode('utf-8')) return web.Response(body='OK'.encode('utf-8'))

View file

@ -0,0 +1,142 @@
from aiohttp import web
from cbpi_api import request_mapping
from cbpi_api.exceptions import CBPiException
from http_endpoints.http_curd_endpoints import HttpCrudEndpoints
class SensorHttpEndpoints(HttpCrudEndpoints):
def __init__(self, cbpi):
super().__init__(cbpi)
self.controller = cbpi.sensor
self.cbpi.register(self, "/sensor")
@request_mapping(path="/types", auth_required=False)
async def get_types(self, request):
"""
---
description: Get all sensor types
tags:
- Sensor
responses:
"200":
description: successful operation
"""
return await super().get_types(request)
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request):
"""
---
description: Get all sensor
tags:
- Sensor
responses:
"204":
description: successful operation
"""
return await super().http_get_all(request)
@request_mapping(path="/{id:\d+}", auth_required=False)
async def http_get_one(self, request):
"""
---
description: Get an sensor
tags:
- Sensor
parameters:
- name: "id"
in: "path"
description: "Sensor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
return await super().http_get_one(request)
@request_mapping(path="/", method="POST", auth_required=False)
async def http_add(self, request):
"""
---
description: Get one sensor
tags:
- Sensor
parameters:
- in: body
name: body
description: Created an sensor
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
type: object
responses:
"204":
description: successful operation
"""
return await super().http_add(request)
@request_mapping(path="/{id}", method="PUT", auth_required=False)
async def http_update(self, request):
"""
---
description: Update an sensor
tags:
- Sensor
parameters:
- name: "id"
in: "path"
description: "Sensor ID"
required: true
type: "integer"
format: "int64"
- in: body
name: body
description: Update an sensor
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
type: object
responses:
"200":
description: successful operation
"""
return await super().http_update(request)
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
async def http_delete_one(self, request):
"""
---
description: Delete an sensor
tags:
- Sensor
parameters:
- name: "id"
in: "path"
description: "Sensor ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
return await super().http_delete_one(request)

View file

@ -0,0 +1,228 @@
from aiohttp import web
from cbpi_api import request_mapping
from cbpi_api.exceptions import CBPiException
from http_endpoints.http_curd_endpoints import HttpCrudEndpoints
class StepHttpEndpoints(HttpCrudEndpoints):
def __init__(self, cbpi):
super().__init__(cbpi)
self.controller = cbpi.step
self.cbpi.register(self, "/step")
@request_mapping(path="/types", auth_required=False)
async def get_types(self, request):
"""
---
description: Get all step types
tags:
- Step
responses:
"200":
description: successful operation
"""
return await super().get_types(request)
@request_mapping(path="/", auth_required=False)
async def http_get_all(self, request):
"""
---
description: Switch step on
tags:
- Step
parameters:
- name: "id"
in: "path"
description: "step ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
return await super().http_get_all(request)
@request_mapping(path="/{id:\d+}", auth_required=False)
async def http_get_one(self, request):
"""
---
description: Get one step
tags:
- Step
parameters:
- name: "id"
in: "path"
description: "step ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"405":
description: invalid HTTP Met
"""
return await super().http_get_one(request)
@request_mapping(path="/", method="POST", auth_required=False)
async def http_add(self, request):
"""
---
description: Get one step
tags:
- Step
parameters:
- in: body
name: body
description: Created an step
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
type: object
responses:
"204":
description: successful operation
"""
return await super().http_add(request)
@request_mapping(path="/{id}", method="PUT", auth_required=False)
async def http_update(self, request):
"""
---
description: Update an step
tags:
- Step
parameters:
- name: "id"
in: "path"
description: "step ID"
required: true
type: "integer"
format: "int64"
- in: body
name: body
description: Update an step
required: false
schema:
type: object
properties:
name:
type: string
type:
type: string
config:
type: object
responses:
"200":
description: successful operation
"""
return await super().http_update(request)
@request_mapping(path="/{id}", method="DELETE", auth_required=False)
async def http_delete_one(self, request):
"""
---
description: Delete a step
tags:
- Step
parameters:
- name: "id"
in: "path"
description: "Step ID"
required: true
type: "integer"
format: "int64"
responses:
"204":
description: successful operation
"""
return await super().http_delete_one(request)
@request_mapping(path="/action", auth_required=False)
async def http_action(self, request):
"""
---
description: Call step action
tags:
- Step
responses:
"204":
description: successful operation
"""
await self.cbpi.bus.fire("step/action", action="test")
return web.Response(text="OK")
@request_mapping(path="/start", auth_required=False)
async def http_start(self, request):
"""
---
description: Start Brewing Process
tags:
- Step
responses:
"204":
description: successful operation
"""
if self.controller.is_running():
raise CBPiException("Brewing Process Already Running")
result = await self.cbpi.bus.fire("step/start")
r = result.get("core.controller.step_controller.start")
if r[0] is True:
return web.Response(status=204)
else:
raise CBPiException("Failed to start brewing process")
@request_mapping(path="/reset", auth_required=False)
async def http_reset(self, request):
"""
---
description: Reset Brewing Process
tags:
- Step
responses:
"204":
description: successful operation
"""
await self.cbpi.bus.fire("step/reset")
return web.Response(text="OK")
@request_mapping(path="/next", auth_required=False)
async def http_next(self, request):
"""
---
description: Start next step
tags:
- Step
responses:
"204":
description: successful operation
"""
await self.cbpi.bus.fire("step/next")
return web.Response(status=204)
@request_mapping(path="/stop", auth_required=False)
async def http_stop(self, request):
"""
---
description: Stop next step
tags:
- Step
responses:
"204":
description: successful operation
"""
await self.cbpi.bus.fire("step/stop")
return web.Response(status=204)

View file

@ -1,39 +0,0 @@
tags:
- user
summary: Create user111
description: This can only be done by the logged in user.
operationId: examples.api.api.createUser
produces:
- application/json
parameters:
- in: body
name: body
description: Created user object
required: false
schema:
type: object
properties:
id:
type: integer
format: int64
username:
type:
- "string"
- "null"
firstName:
type: string
lastName:
type: string
email:
type: string
password:
type: string
phone:
type: string
userStatus:
type: integer
format: int32
description: User Status
responses:
"201":
description: successful operation

View file

@ -1,7 +1,5 @@
from json import JSONEncoder from json import JSONEncoder
class ComplexEncoder(JSONEncoder): class ComplexEncoder(JSONEncoder):
@ -16,10 +14,10 @@ class ComplexEncoder(JSONEncoder):
# return obj.reprJSON() # return obj.reprJSON()
#elif isinstance(obj, ActorModel): #elif isinstance(obj, ActorModel):
# return None # return None
elif hasattr(obj, "callback"): #elif hasattr(obj, "callback"):
return obj() # return obj()
else: else:
return None return None
except TypeError as e: except TypeError:
pass pass
return None return None

View file

@ -1,72 +1,18 @@
from pprint import pprint
from cbpi_api import *
from core.utils.encoder import ComplexEncoder from core.utils.encoder import ComplexEncoder
__all__ = ['load_config',"json_dumps", "parse_props"] __all__ = ['load_config',"json_dumps"]
import json import json
from json import JSONEncoder
import yaml import yaml
from core.database.model import DBModel, ActorModel
def load_config(fname): def load_config(fname):
try: try:
with open(fname, 'rt') as f: with open(fname, 'rt') as f:
data = yaml.load(f) data = yaml.load(f)
return data return data
except Exception as e: except Exception as e:
pass pass
def json_dumps(obj): def json_dumps(obj):
return json.dumps(obj, cls=ComplexEncoder) return json.dumps(obj, cls=ComplexEncoder)
def parse_props(self, cls):
name = cls.__name__
result = {"name": name, "class": cls, "properties": [], "actions": []}
tmpObj = cls()
members = [attr for attr in dir(tmpObj) if not callable(getattr(tmpObj, attr)) and not attr.startswith("__")]
for m in members:
if isinstance(tmpObj.__getattribute__(m), Property.Number):
t = tmpObj.__getattribute__(m)
result["properties"].append(
{"name": m, "label": t.label, "type": "number", "configurable": t.configurable, "description": t.description, "default_value": t.default_value})
elif isinstance(tmpObj.__getattribute__(m), Property.Text):
t = tmpObj.__getattribute__(m)
result["properties"].append(
{"name": m, "label": t.label, "type": "text", "configurable": t.configurable, "default_value": t.default_value, "description": t.description})
elif isinstance(tmpObj.__getattribute__(m), Property.Select):
t = tmpObj.__getattribute__(m)
result["properties"].append(
{"name": m, "label": t.label, "type": "select", "configurable": True, "options": t.options, "description": t.description})
elif isinstance(tmpObj.__getattribute__(m), Property.Actor):
t = tmpObj.__getattribute__(m)
result["properties"].append({"name": m, "label": t.label, "type": "actor", "configurable": t.configurable, "description": t.description})
elif isinstance(tmpObj.__getattribute__(m), Property.Sensor):
t = tmpObj.__getattribute__(m)
result["properties"].append({"name": m, "label": t.label, "type": "sensor", "configurable": t.configurable, "description": t.description})
elif isinstance(tmpObj.__getattribute__(m), Property.Kettle):
t = tmpObj.__getattribute__(m)
result["properties"].append({"name": m, "label": t.label, "type": "kettle", "configurable": t.configurable, "description": t.description})
for method_name, method in cls.__dict__.items():
if hasattr(method, "action"):
key = method.__getattribute__("key")
parameters = method.__getattribute__("parameters")
result["actions"].append({"method": method_name, "label": key, "parameters": parameters})

View file

@ -27,7 +27,6 @@ class CBPiWebSocket:
def send(self, data): def send(self, data):
for ws in self._clients: for ws in self._clients:
async def send_data(ws, data): async def send_data(ws, data):
await ws.send_str(data) await ws.send_str(data)
self.cbpi.app.loop.create_task(send_data(ws, data)) self.cbpi.app.loop.create_task(send_data(ws, data))

Binary file not shown.

View file

@ -162,7 +162,7 @@
<dl class="class"> <dl class="class">
<dt id="core.controller.sensor_controller.SensorController"> <dt id="core.controller.sensor_controller.SensorController">
<em class="property">class </em><code class="descclassname">core.controller.sensor_controller.</code><code class="descname">SensorController</code><span class="sig-paren">(</span><em>cbpi</em><span class="sig-paren">)</span><a class="headerlink" href="#core.controller.sensor_controller.SensorController" title="Permalink to this definition"></a></dt> <em class="property">class </em><code class="descclassname">core.controller.sensor_controller.</code><code class="descname">SensorController</code><span class="sig-paren">(</span><em>cbpi</em><span class="sig-paren">)</span><a class="headerlink" href="#core.controller.sensor_controller.SensorController" title="Permalink to this definition"></a></dt>
<dd><p>Bases: <code class="xref py py-class docutils literal notranslate"><span class="pre">core.controller.crud_controller.CRUDController</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">core.http_endpoints.http_api.HttpAPI</span></code></p> <dd><p>Bases: <code class="xref py py-class docutils literal notranslate"><span class="pre">core.controller.crud_controller.CRUDController</span></code>, <code class="xref py py-class docutils literal notranslate"><span class="pre">core.http_endpoints.http_api.HttpCrudEndpoints</span></code></p>
<dl class="method"> <dl class="method">
<dt id="core.controller.sensor_controller.SensorController.get_value"> <dt id="core.controller.sensor_controller.SensorController.get_value">
<code class="descname">get_value</code><span class="sig-paren">(</span><em>id</em><span class="sig-paren">)</span><a class="headerlink" href="#core.controller.sensor_controller.SensorController.get_value" title="Permalink to this definition"></a></dt> <code class="descname">get_value</code><span class="sig-paren">(</span><em>id</em><span class="sig-paren">)</span><a class="headerlink" href="#core.controller.sensor_controller.SensorController.get_value" title="Permalink to this definition"></a></dt>

View file

@ -1,49 +1,24 @@
2019-01-02 00:44:06,10 2019-01-02 20:34:10,10
2019-01-02 00:44:11,10 2019-01-02 20:34:15,10
2019-01-02 00:44:16,10 2019-01-02 20:34:20,10
2019-01-02 00:44:21,10 2019-01-02 20:34:25,10
2019-01-02 00:44:26,10 2019-01-02 20:34:32,10
2019-01-02 00:44:31,10 2019-01-02 20:34:37,10
2019-01-02 00:44:36,10 2019-01-02 20:34:42,10
2019-01-02 00:44:41,10 2019-01-02 20:34:47,10
2019-01-02 00:44:46,10 2019-01-02 20:34:52,10
2019-01-02 00:44:51,10 2019-01-02 20:34:57,10
2019-01-02 00:44:56,10 2019-01-02 20:35:02,10
2019-01-02 00:45:01,10 2019-01-02 20:35:07,10
2019-01-02 00:45:06,10 2019-01-02 20:35:12,10
2019-01-02 00:45:11,10 2019-01-02 20:35:17,10
2019-01-02 00:45:16,10 2019-01-02 20:35:22,10
2019-01-02 00:45:21,10 2019-01-02 20:35:30,10
2019-01-02 00:45:26,10 2019-01-02 20:35:35,10
2019-01-02 00:45:31,10 2019-01-02 20:35:40,10
2019-01-02 00:45:36,10 2019-01-02 20:35:45,10
2019-01-02 00:45:41,10 2019-01-02 20:35:50,10
2019-01-02 00:45:46,10 2019-01-02 20:35:55,10
2019-01-02 00:45:51,10 2019-01-02 20:36:00,10
2019-01-02 00:45:56,10 2019-01-02 20:36:05,10
2019-01-02 00:46:01,10 2019-01-02 20:36:10,10
2019-01-02 00:46:06,10
2019-01-02 00:46:11,10
2019-01-02 00:46:16,10
2019-01-02 00:46:21,10
2019-01-02 00:46:26,10
2019-01-02 00:46:31,10
2019-01-02 00:46:36,10
2019-01-02 00:46:41,10
2019-01-02 00:46:46,10
2019-01-02 00:46:51,10
2019-01-02 00:46:56,10
2019-01-02 00:47:01,10
2019-01-02 00:47:06,10
2019-01-02 00:47:11,10
2019-01-02 00:47:16,10
2019-01-02 00:47:21,10
2019-01-02 00:47:26,10
2019-01-02 00:47:31,10
2019-01-02 00:47:36,10
2019-01-02 00:47:41,10
2019-01-02 00:47:46,10
2019-01-02 00:47:51,10
2019-01-02 00:47:56,10
2019-01-02 00:48:01,10
2019-01-02 00:48:06,10

View file

@ -1,86 +1,86 @@
2019-01-02 00:36:56,10 2019-01-02 20:26:40,10
2019-01-02 00:37:01,10 2019-01-02 20:26:45,10
2019-01-02 00:37:06,10 2019-01-02 20:26:50,10
2019-01-02 00:37:11,10 2019-01-02 20:26:55,10
2019-01-02 00:37:16,10 2019-01-02 20:27:00,10
2019-01-02 00:37:21,10 2019-01-02 20:27:05,10
2019-01-02 00:37:26,10 2019-01-02 20:27:10,10
2019-01-02 00:37:31,10 2019-01-02 20:27:15,10
2019-01-02 00:37:36,10 2019-01-02 20:27:20,10
2019-01-02 00:37:41,10 2019-01-02 20:27:25,10
2019-01-02 00:37:46,10 2019-01-02 20:27:30,10
2019-01-02 00:37:51,10 2019-01-02 20:27:35,10
2019-01-02 00:37:56,10 2019-01-02 20:27:40,10
2019-01-02 00:38:01,10 2019-01-02 20:27:45,10
2019-01-02 00:38:06,10 2019-01-02 20:27:51,10
2019-01-02 00:38:11,10 2019-01-02 20:27:56,10
2019-01-02 00:38:16,10 2019-01-02 20:28:01,10
2019-01-02 00:38:21,10 2019-01-02 20:28:06,10
2019-01-02 00:38:26,10 2019-01-02 20:28:11,10
2019-01-02 00:38:31,10 2019-01-02 20:28:16,10
2019-01-02 00:38:36,10 2019-01-02 20:28:21,10
2019-01-02 00:38:41,10 2019-01-02 20:28:26,10
2019-01-02 00:38:46,10 2019-01-02 20:28:31,10
2019-01-02 00:38:51,10 2019-01-02 20:28:36,10
2019-01-02 00:38:56,10 2019-01-02 20:28:41,10
2019-01-02 00:39:01,10 2019-01-02 20:28:46,10
2019-01-02 00:39:06,10 2019-01-02 20:28:51,10
2019-01-02 00:39:11,10 2019-01-02 20:28:56,10
2019-01-02 00:39:16,10 2019-01-02 20:29:01,10
2019-01-02 00:39:21,10 2019-01-02 20:29:06,10
2019-01-02 00:39:26,10 2019-01-02 20:29:11,10
2019-01-02 00:39:31,10 2019-01-02 20:29:16,10
2019-01-02 00:39:36,10 2019-01-02 20:29:21,10
2019-01-02 00:39:41,10 2019-01-02 20:29:26,10
2019-01-02 00:39:46,10 2019-01-02 20:29:31,10
2019-01-02 00:39:51,10 2019-01-02 20:29:36,10
2019-01-02 00:39:56,10 2019-01-02 20:29:41,10
2019-01-02 00:40:01,10 2019-01-02 20:29:46,10
2019-01-02 00:40:06,10 2019-01-02 20:29:51,10
2019-01-02 00:40:11,10 2019-01-02 20:29:56,10
2019-01-02 00:40:16,10 2019-01-02 20:30:01,10
2019-01-02 00:40:21,10 2019-01-02 20:30:06,10
2019-01-02 00:40:26,10 2019-01-02 20:30:11,10
2019-01-02 00:40:31,10 2019-01-02 20:30:16,10
2019-01-02 00:40:36,10 2019-01-02 20:30:21,10
2019-01-02 00:40:41,10 2019-01-02 20:30:26,10
2019-01-02 00:40:46,10 2019-01-02 20:30:31,10
2019-01-02 00:40:51,10 2019-01-02 20:30:36,10
2019-01-02 00:40:56,10 2019-01-02 20:30:41,10
2019-01-02 00:41:01,10 2019-01-02 20:30:46,10
2019-01-02 00:41:06,10 2019-01-02 20:30:51,10
2019-01-02 00:41:11,10 2019-01-02 20:30:56,10
2019-01-02 00:41:16,10 2019-01-02 20:31:01,10
2019-01-02 00:41:21,10 2019-01-02 20:31:06,10
2019-01-02 00:41:26,10 2019-01-02 20:31:11,10
2019-01-02 00:41:31,10 2019-01-02 20:31:16,10
2019-01-02 00:41:36,10 2019-01-02 20:31:21,10
2019-01-02 00:41:41,10 2019-01-02 20:31:26,10
2019-01-02 00:41:46,10 2019-01-02 20:31:31,10
2019-01-02 00:41:51,10 2019-01-02 20:31:36,10
2019-01-02 00:41:56,10 2019-01-02 20:31:41,10
2019-01-02 00:42:01,10 2019-01-02 20:31:46,10
2019-01-02 00:42:06,10 2019-01-02 20:31:51,10
2019-01-02 00:42:11,10 2019-01-02 20:31:56,10
2019-01-02 00:42:16,10 2019-01-02 20:32:01,10
2019-01-02 00:42:21,10 2019-01-02 20:32:06,10
2019-01-02 00:42:26,10 2019-01-02 20:32:11,10
2019-01-02 00:42:31,10 2019-01-02 20:32:16,10
2019-01-02 00:42:36,10 2019-01-02 20:32:21,10
2019-01-02 00:42:41,10 2019-01-02 20:32:26,10
2019-01-02 00:42:46,10 2019-01-02 20:32:31,10
2019-01-02 00:42:51,10 2019-01-02 20:32:36,10
2019-01-02 00:42:56,10 2019-01-02 20:32:41,10
2019-01-02 00:43:01,10 2019-01-02 20:33:05,10
2019-01-02 00:43:06,10 2019-01-02 20:33:10,10
2019-01-02 00:43:11,10 2019-01-02 20:33:15,10
2019-01-02 00:43:16,10 2019-01-02 20:33:20,10
2019-01-02 00:43:21,10 2019-01-02 20:33:25,10
2019-01-02 00:43:26,10 2019-01-02 20:33:30,10
2019-01-02 00:43:31,10 2019-01-02 20:33:35,10
2019-01-02 00:43:36,10 2019-01-02 20:33:40,10
2019-01-02 00:43:41,10 2019-01-02 20:33:45,10
2019-01-02 00:43:46,10 2019-01-02 20:33:50,10
2019-01-02 00:43:51,10 2019-01-02 20:33:55,10
2019-01-02 00:43:56,10 2019-01-02 20:34:00,10
2019-01-02 00:44:01,10 2019-01-02 20:34:05,10

View file

@ -1,86 +1,86 @@
2019-01-01 23:05:37,10 2019-01-02 18:48:13,10
2019-01-01 23:19:02,10 2019-01-02 18:48:18,10
2019-01-01 23:19:07,10 2019-01-02 18:48:23,10
2019-01-01 23:19:12,10 2019-01-02 18:48:28,10
2019-01-01 23:19:17,10 2019-01-02 18:48:33,10
2019-01-01 23:19:22,10 2019-01-02 18:48:38,10
2019-01-01 23:19:27,10 2019-01-02 18:48:43,10
2019-01-01 23:19:32,10 2019-01-02 18:48:48,10
2019-01-01 23:19:37,10 2019-01-02 18:48:53,10
2019-01-01 23:19:42,10 2019-01-02 18:48:58,10
2019-01-01 23:19:47,10 2019-01-02 18:49:03,10
2019-01-01 23:19:52,10 2019-01-02 18:49:07,10
2019-01-01 23:19:57,10 2019-01-02 18:49:07,10
2019-01-01 23:20:02,10 2019-01-02 18:49:07,10
2019-01-01 23:20:07,10 2019-01-02 18:49:07,10
2019-01-01 23:20:12,10 2019-01-02 18:49:07,10
2019-01-01 23:21:07,10 2019-01-02 18:49:07,10
2019-01-01 23:21:12,10 2019-01-02 18:49:07,10
2019-01-01 23:21:17,10 2019-01-02 18:49:07,10
2019-01-01 23:21:22,10 2019-01-02 18:49:07,10
2019-01-01 23:21:27,10 2019-01-02 18:49:07,10
2019-01-01 23:21:32,10 2019-01-02 18:49:07,10
2019-01-01 23:21:37,10 2019-01-02 18:49:08,10
2019-01-01 23:21:42,10 2019-01-02 18:49:13,10
2019-01-01 23:21:47,10 2019-01-02 18:49:18,10
2019-01-01 23:21:52,10 2019-01-02 18:49:23,10
2019-01-01 23:21:57,10 2019-01-02 18:49:28,10
2019-01-01 23:22:02,10 2019-01-02 18:49:33,10
2019-01-01 23:22:07,10 2019-01-02 18:49:38,10
2019-01-01 23:22:12,10 2019-01-02 18:49:43,10
2019-01-01 23:22:17,10 2019-01-02 18:49:48,10
2019-01-01 23:22:22,10 2019-01-02 18:49:53,10
2019-01-01 23:22:27,10 2019-01-02 18:49:58,10
2019-01-01 23:22:32,10 2019-01-02 18:49:58,10
2019-01-01 23:22:37,10 2019-01-02 18:49:58,10
2019-01-01 23:22:42,10 2019-01-02 18:49:58,10
2019-01-01 23:22:47,10 2019-01-02 18:49:58,10
2019-01-01 23:22:52,10 2019-01-02 18:49:58,10
2019-01-01 23:22:57,10 2019-01-02 18:49:58,10
2019-01-01 23:23:02,10 2019-01-02 18:49:58,10
2019-01-01 23:23:10,10 2019-01-02 18:49:58,10
2019-01-01 23:23:15,10 2019-01-02 18:49:58,10
2019-01-01 23:23:20,10 2019-01-02 18:49:58,10
2019-01-01 23:23:25,10 2019-01-02 18:49:58,10
2019-01-01 23:23:30,10 2019-01-02 18:50:03,10
2019-01-01 23:23:35,10 2019-01-02 18:50:08,10
2019-01-01 23:23:40,10 2019-01-02 18:50:13,10
2019-01-01 23:23:45,10 2019-01-02 18:50:18,10
2019-01-01 23:23:50,10 2019-01-02 18:50:23,10
2019-01-01 23:23:55,10 2019-01-02 18:50:28,10
2019-01-01 23:24:00,10 2019-01-02 18:50:33,10
2019-01-01 23:24:05,10 2019-01-02 18:50:38,10
2019-01-01 23:24:10,10 2019-01-02 18:50:43,10
2019-01-01 23:24:15,10 2019-01-02 18:50:48,10
2019-01-01 23:24:20,10 2019-01-02 18:50:53,10
2019-01-01 23:24:25,10 2019-01-02 18:50:58,10
2019-01-01 23:24:30,10 2019-01-02 18:51:03,10
2019-01-01 23:24:35,10 2019-01-02 18:51:08,10
2019-01-01 23:24:40,10 2019-01-02 18:51:13,10
2019-01-01 23:24:45,10 2019-01-02 18:51:18,10
2019-01-01 23:24:50,10 2019-01-02 18:51:23,10
2019-01-01 23:24:55,10 2019-01-02 18:51:28,10
2019-01-01 23:25:00,10 2019-01-02 18:51:29,10
2019-01-01 23:25:05,10 2019-01-02 18:51:29,10
2019-01-01 23:25:10,10 2019-01-02 18:51:29,10
2019-01-01 23:25:15,10 2019-01-02 18:51:29,10
2019-01-01 23:25:20,10 2019-01-02 18:51:29,10
2019-01-01 23:25:25,10 2019-01-02 18:51:29,10
2019-01-01 23:25:30,10 2019-01-02 18:51:29,10
2019-01-01 23:25:42,10 2019-01-02 18:51:29,10
2019-01-01 23:25:47,10 2019-01-02 18:51:29,10
2019-01-01 23:25:52,10 2019-01-02 18:51:29,10
2019-01-01 23:25:57,10 2019-01-02 18:51:29,10
2019-01-01 23:26:02,10 2019-01-02 18:51:33,10
2019-01-01 23:26:07,10 2019-01-02 18:51:38,10
2019-01-01 23:26:12,10 2019-01-02 18:51:43,10
2019-01-01 23:26:17,10 2019-01-02 18:51:43,10
2019-01-01 23:26:22,10 2019-01-02 18:51:43,10
2019-01-01 23:26:27,10 2019-01-02 18:51:43,10
2019-01-01 23:26:32,10 2019-01-02 18:51:43,10
2019-01-01 23:26:37,10 2019-01-02 18:51:43,10
2019-01-01 23:26:42,10 2019-01-02 18:51:43,10
2019-01-01 23:26:47,10 2019-01-02 18:51:43,10
2019-01-01 23:26:52,10 2019-01-02 18:51:43,10
2019-01-01 23:26:57,10 2019-01-02 18:51:43,10
2019-01-01 23:27:02,10 2019-01-02 18:51:43,10

View file

@ -1,86 +1,86 @@
2019-01-02 00:29:45,10 2019-01-02 19:43:47,10
2019-01-02 00:29:50,10 2019-01-02 19:43:52,10
2019-01-02 00:29:55,10 2019-01-02 19:43:57,10
2019-01-02 00:30:00,10 2019-01-02 19:44:02,10
2019-01-02 00:30:05,10 2019-01-02 19:44:07,10
2019-01-02 00:30:10,10 2019-01-02 19:44:12,10
2019-01-02 00:30:15,10 2019-01-02 19:44:17,10
2019-01-02 00:30:20,10 2019-01-02 19:44:22,10
2019-01-02 00:30:25,10 2019-01-02 19:44:27,10
2019-01-02 00:30:30,10 2019-01-02 19:44:32,10
2019-01-02 00:30:35,10 2019-01-02 19:44:37,10
2019-01-02 00:30:40,10 2019-01-02 19:44:42,10
2019-01-02 00:30:45,10 2019-01-02 19:44:47,10
2019-01-02 00:30:50,10 2019-01-02 19:44:52,10
2019-01-02 00:30:55,10 2019-01-02 19:44:57,10
2019-01-02 00:31:00,10 2019-01-02 19:45:02,10
2019-01-02 00:31:05,10 2019-01-02 19:45:07,10
2019-01-02 00:31:10,10 2019-01-02 19:45:12,10
2019-01-02 00:31:15,10 2019-01-02 19:45:17,10
2019-01-02 00:31:20,10 2019-01-02 19:45:22,10
2019-01-02 00:31:25,10 2019-01-02 19:45:27,10
2019-01-02 00:31:30,10 2019-01-02 20:21:15,10
2019-01-02 00:31:35,10 2019-01-02 20:21:20,10
2019-01-02 00:31:40,10 2019-01-02 20:21:25,10
2019-01-02 00:31:45,10 2019-01-02 20:21:30,10
2019-01-02 00:31:50,10 2019-01-02 20:21:35,10
2019-01-02 00:31:55,10 2019-01-02 20:21:40,10
2019-01-02 00:32:00,10 2019-01-02 20:21:45,10
2019-01-02 00:32:05,10 2019-01-02 20:21:50,10
2019-01-02 00:32:10,10 2019-01-02 20:21:55,10
2019-01-02 00:32:15,10 2019-01-02 20:22:00,10
2019-01-02 00:32:20,10 2019-01-02 20:22:05,10
2019-01-02 00:32:25,10 2019-01-02 20:22:10,10
2019-01-02 00:32:30,10 2019-01-02 20:22:15,10
2019-01-02 00:32:35,10 2019-01-02 20:22:20,10
2019-01-02 00:32:40,10 2019-01-02 20:22:25,10
2019-01-02 00:32:45,10 2019-01-02 20:22:30,10
2019-01-02 00:32:51,10 2019-01-02 20:22:35,10
2019-01-02 00:32:56,10 2019-01-02 20:22:40,10
2019-01-02 00:33:01,10 2019-01-02 20:22:45,10
2019-01-02 00:33:06,10 2019-01-02 20:22:50,10
2019-01-02 00:33:11,10 2019-01-02 20:22:55,10
2019-01-02 00:33:16,10 2019-01-02 20:23:00,10
2019-01-02 00:33:21,10 2019-01-02 20:23:05,10
2019-01-02 00:33:26,10 2019-01-02 20:23:10,10
2019-01-02 00:33:31,10 2019-01-02 20:23:15,10
2019-01-02 00:33:36,10 2019-01-02 20:23:20,10
2019-01-02 00:33:41,10 2019-01-02 20:23:25,10
2019-01-02 00:33:46,10 2019-01-02 20:23:30,10
2019-01-02 00:33:51,10 2019-01-02 20:23:35,10
2019-01-02 00:33:56,10 2019-01-02 20:23:40,10
2019-01-02 00:34:01,10 2019-01-02 20:23:45,10
2019-01-02 00:34:06,10 2019-01-02 20:23:50,10
2019-01-02 00:34:11,10 2019-01-02 20:23:55,10
2019-01-02 00:34:16,10 2019-01-02 20:24:00,10
2019-01-02 00:34:21,10 2019-01-02 20:24:05,10
2019-01-02 00:34:26,10 2019-01-02 20:24:10,10
2019-01-02 00:34:31,10 2019-01-02 20:24:15,10
2019-01-02 00:34:36,10 2019-01-02 20:24:20,10
2019-01-02 00:34:41,10 2019-01-02 20:24:25,10
2019-01-02 00:34:46,10 2019-01-02 20:24:30,10
2019-01-02 00:34:51,10 2019-01-02 20:24:35,10
2019-01-02 00:34:56,10 2019-01-02 20:24:40,10
2019-01-02 00:35:01,10 2019-01-02 20:24:45,10
2019-01-02 00:35:06,10 2019-01-02 20:24:50,10
2019-01-02 00:35:11,10 2019-01-02 20:24:55,10
2019-01-02 00:35:16,10 2019-01-02 20:25:00,10
2019-01-02 00:35:21,10 2019-01-02 20:25:05,10
2019-01-02 00:35:26,10 2019-01-02 20:25:10,10
2019-01-02 00:35:31,10 2019-01-02 20:25:15,10
2019-01-02 00:35:36,10 2019-01-02 20:25:20,10
2019-01-02 00:35:41,10 2019-01-02 20:25:25,10
2019-01-02 00:35:46,10 2019-01-02 20:25:30,10
2019-01-02 00:35:51,10 2019-01-02 20:25:35,10
2019-01-02 00:35:56,10 2019-01-02 20:25:40,10
2019-01-02 00:36:01,10 2019-01-02 20:25:45,10
2019-01-02 00:36:06,10 2019-01-02 20:25:50,10
2019-01-02 00:36:11,10 2019-01-02 20:25:55,10
2019-01-02 00:36:16,10 2019-01-02 20:26:00,10
2019-01-02 00:36:21,10 2019-01-02 20:26:05,10
2019-01-02 00:36:26,10 2019-01-02 20:26:10,10
2019-01-02 00:36:31,10 2019-01-02 20:26:15,10
2019-01-02 00:36:36,10 2019-01-02 20:26:20,10
2019-01-02 00:36:41,10 2019-01-02 20:26:25,10
2019-01-02 00:36:46,10 2019-01-02 20:26:30,10
2019-01-02 00:36:51,10 2019-01-02 20:26:35,10

View file

@ -1,86 +1,86 @@
2019-01-02 00:22:01,10 2019-01-02 19:36:04,10
2019-01-02 00:22:06,10 2019-01-02 19:36:09,10
2019-01-02 00:22:11,10 2019-01-02 19:36:14,10
2019-01-02 00:22:16,10 2019-01-02 19:36:19,10
2019-01-02 00:22:21,10 2019-01-02 19:36:24,10
2019-01-02 00:22:26,10 2019-01-02 19:36:29,10
2019-01-02 00:22:31,10 2019-01-02 19:36:34,10
2019-01-02 00:22:36,10 2019-01-02 19:36:39,10
2019-01-02 00:22:41,10 2019-01-02 19:36:44,10
2019-01-02 00:22:46,10 2019-01-02 19:36:49,10
2019-01-02 00:22:51,10 2019-01-02 19:36:54,10
2019-01-02 00:23:30,10 2019-01-02 19:36:59,10
2019-01-02 00:23:35,10 2019-01-02 19:37:04,10
2019-01-02 00:23:40,10 2019-01-02 19:37:09,10
2019-01-02 00:23:45,10 2019-01-02 19:37:14,10
2019-01-02 00:23:50,10 2019-01-02 19:37:19,10
2019-01-02 00:23:55,10 2019-01-02 19:37:24,10
2019-01-02 00:24:00,10 2019-01-02 19:37:30,10
2019-01-02 00:24:05,10 2019-01-02 19:37:35,10
2019-01-02 00:24:10,10 2019-01-02 19:37:40,10
2019-01-02 00:24:15,10 2019-01-02 19:37:45,10
2019-01-02 00:24:20,10 2019-01-02 19:37:50,10
2019-01-02 00:24:25,10 2019-01-02 19:37:55,10
2019-01-02 00:24:30,10 2019-01-02 19:38:00,10
2019-01-02 00:24:35,10 2019-01-02 19:38:05,10
2019-01-02 00:24:40,10 2019-01-02 19:38:10,10
2019-01-02 00:24:45,10 2019-01-02 19:38:15,10
2019-01-02 00:24:50,10 2019-01-02 19:38:20,10
2019-01-02 00:24:55,10 2019-01-02 19:38:25,10
2019-01-02 00:25:00,10 2019-01-02 19:38:30,10
2019-01-02 00:25:05,10 2019-01-02 19:38:35,10
2019-01-02 00:25:10,10 2019-01-02 19:38:44,10
2019-01-02 00:25:15,10 2019-01-02 19:38:49,10
2019-01-02 00:25:20,10 2019-01-02 19:38:54,10
2019-01-02 00:25:25,10 2019-01-02 19:38:59,10
2019-01-02 00:25:30,10 2019-01-02 19:39:04,10
2019-01-02 00:25:35,10 2019-01-02 19:39:09,10
2019-01-02 00:25:40,10 2019-01-02 19:39:14,10
2019-01-02 00:25:45,10 2019-01-02 19:39:22,10
2019-01-02 00:25:50,10 2019-01-02 19:39:27,10
2019-01-02 00:25:55,10 2019-01-02 19:39:32,10
2019-01-02 00:26:00,10 2019-01-02 19:39:37,10
2019-01-02 00:26:05,10 2019-01-02 19:39:42,10
2019-01-02 00:26:10,10 2019-01-02 19:39:47,10
2019-01-02 00:26:15,10 2019-01-02 19:39:52,10
2019-01-02 00:26:20,10 2019-01-02 19:39:58,10
2019-01-02 00:26:25,10 2019-01-02 19:40:03,10
2019-01-02 00:26:30,10 2019-01-02 19:40:08,10
2019-01-02 00:26:35,10 2019-01-02 19:40:13,10
2019-01-02 00:26:40,10 2019-01-02 19:40:18,10
2019-01-02 00:26:45,10 2019-01-02 19:40:23,10
2019-01-02 00:26:50,10 2019-01-02 19:40:28,10
2019-01-02 00:26:55,10 2019-01-02 19:40:33,10
2019-01-02 00:27:00,10 2019-01-02 19:40:43,10
2019-01-02 00:27:05,10 2019-01-02 19:40:48,10
2019-01-02 00:27:10,10 2019-01-02 19:40:53,10
2019-01-02 00:27:15,10 2019-01-02 19:40:58,10
2019-01-02 00:27:20,10 2019-01-02 19:41:03,10
2019-01-02 00:27:25,10 2019-01-02 19:41:08,10
2019-01-02 00:27:30,10 2019-01-02 19:41:20,10
2019-01-02 00:27:35,10 2019-01-02 19:41:25,10
2019-01-02 00:27:40,10 2019-01-02 19:41:36,10
2019-01-02 00:27:45,10 2019-01-02 19:41:41,10
2019-01-02 00:27:50,10 2019-01-02 19:41:46,10
2019-01-02 00:27:55,10 2019-01-02 19:41:51,10
2019-01-02 00:28:00,10 2019-01-02 19:41:56,10
2019-01-02 00:28:05,10 2019-01-02 19:42:01,10
2019-01-02 00:28:10,10 2019-01-02 19:42:06,10
2019-01-02 00:28:15,10 2019-01-02 19:42:11,10
2019-01-02 00:28:20,10 2019-01-02 19:42:16,10
2019-01-02 00:28:25,10 2019-01-02 19:42:21,10
2019-01-02 00:28:30,10 2019-01-02 19:42:26,10
2019-01-02 00:28:35,10 2019-01-02 19:42:31,10
2019-01-02 00:28:40,10 2019-01-02 19:42:36,10
2019-01-02 00:28:45,10 2019-01-02 19:42:41,10
2019-01-02 00:28:50,10 2019-01-02 19:42:46,10
2019-01-02 00:28:55,10 2019-01-02 19:42:51,10
2019-01-02 00:29:00,10 2019-01-02 19:42:56,10
2019-01-02 00:29:05,10 2019-01-02 19:43:01,10
2019-01-02 00:29:10,10 2019-01-02 19:43:06,10
2019-01-02 00:29:15,10 2019-01-02 19:43:11,10
2019-01-02 00:29:20,10 2019-01-02 19:43:22,10
2019-01-02 00:29:25,10 2019-01-02 19:43:27,10
2019-01-02 00:29:30,10 2019-01-02 19:43:32,10
2019-01-02 00:29:35,10 2019-01-02 19:43:37,10
2019-01-02 00:29:40,10 2019-01-02 19:43:42,10

View file

@ -1,86 +1,86 @@
2019-01-02 00:14:36,10 2019-01-02 19:28:35,10
2019-01-02 00:14:41,10 2019-01-02 19:28:40,10
2019-01-02 00:14:46,10 2019-01-02 19:28:47,10
2019-01-02 00:14:51,10 2019-01-02 19:28:52,10
2019-01-02 00:14:56,10 2019-01-02 19:28:57,10
2019-01-02 00:15:01,10 2019-01-02 19:29:02,10
2019-01-02 00:15:06,10 2019-01-02 19:29:07,10
2019-01-02 00:15:11,10 2019-01-02 19:29:12,10
2019-01-02 00:15:16,10 2019-01-02 19:29:17,10
2019-01-02 00:15:21,10 2019-01-02 19:29:22,10
2019-01-02 00:15:26,10 2019-01-02 19:29:27,10
2019-01-02 00:15:31,10 2019-01-02 19:29:32,10
2019-01-02 00:15:36,10 2019-01-02 19:29:44,10
2019-01-02 00:15:41,10 2019-01-02 19:29:49,10
2019-01-02 00:15:46,10 2019-01-02 19:29:54,10
2019-01-02 00:15:51,10 2019-01-02 19:29:59,10
2019-01-02 00:15:56,10 2019-01-02 19:30:04,10
2019-01-02 00:16:01,10 2019-01-02 19:30:09,10
2019-01-02 00:16:06,10 2019-01-02 19:30:14,10
2019-01-02 00:16:11,10 2019-01-02 19:30:19,10
2019-01-02 00:16:16,10 2019-01-02 19:30:24,10
2019-01-02 00:16:21,10 2019-01-02 19:30:29,10
2019-01-02 00:16:26,10 2019-01-02 19:30:34,10
2019-01-02 00:16:31,10 2019-01-02 19:30:39,10
2019-01-02 00:16:36,10 2019-01-02 19:30:46,10
2019-01-02 00:16:41,10 2019-01-02 19:30:51,10
2019-01-02 00:16:46,10 2019-01-02 19:30:56,10
2019-01-02 00:16:51,10 2019-01-02 19:31:01,10
2019-01-02 00:16:56,10 2019-01-02 19:31:09,10
2019-01-02 00:17:04,10 2019-01-02 19:31:14,10
2019-01-02 00:17:09,10 2019-01-02 19:31:19,10
2019-01-02 00:17:14,10 2019-01-02 19:31:24,10
2019-01-02 00:17:19,10 2019-01-02 19:31:29,10
2019-01-02 00:17:24,10 2019-01-02 19:31:34,10
2019-01-02 00:17:29,10 2019-01-02 19:31:39,10
2019-01-02 00:17:34,10 2019-01-02 19:31:44,10
2019-01-02 00:17:45,10 2019-01-02 19:31:49,10
2019-01-02 00:17:50,10 2019-01-02 19:31:54,10
2019-01-02 00:17:55,10 2019-01-02 19:31:59,10
2019-01-02 00:18:00,10 2019-01-02 19:32:04,10
2019-01-02 00:18:05,10 2019-01-02 19:32:13,10
2019-01-02 00:18:10,10 2019-01-02 19:32:18,10
2019-01-02 00:18:15,10 2019-01-02 19:32:23,10
2019-01-02 00:18:20,10 2019-01-02 19:32:28,10
2019-01-02 00:18:25,10 2019-01-02 19:32:33,10
2019-01-02 00:18:30,10 2019-01-02 19:32:38,10
2019-01-02 00:18:35,10 2019-01-02 19:32:43,10
2019-01-02 00:18:40,10 2019-01-02 19:32:48,10
2019-01-02 00:18:45,10 2019-01-02 19:32:53,10
2019-01-02 00:18:50,10 2019-01-02 19:32:58,10
2019-01-02 00:18:55,10 2019-01-02 19:33:03,10
2019-01-02 00:19:00,10 2019-01-02 19:33:08,10
2019-01-02 00:19:05,10 2019-01-02 19:33:13,10
2019-01-02 00:19:10,10 2019-01-02 19:33:18,10
2019-01-02 00:19:15,10 2019-01-02 19:33:23,10
2019-01-02 00:19:20,10 2019-01-02 19:33:28,10
2019-01-02 00:19:25,10 2019-01-02 19:33:33,10
2019-01-02 00:19:30,10 2019-01-02 19:33:38,10
2019-01-02 00:19:35,10 2019-01-02 19:33:43,10
2019-01-02 00:19:40,10 2019-01-02 19:33:48,10
2019-01-02 00:19:51,10 2019-01-02 19:33:53,10
2019-01-02 00:19:56,10 2019-01-02 19:33:58,10
2019-01-02 00:20:01,10 2019-01-02 19:34:03,10
2019-01-02 00:20:06,10 2019-01-02 19:34:08,10
2019-01-02 00:20:11,10 2019-01-02 19:34:13,10
2019-01-02 00:20:16,10 2019-01-02 19:34:18,10
2019-01-02 00:20:21,10 2019-01-02 19:34:23,10
2019-01-02 00:20:26,10 2019-01-02 19:34:28,10
2019-01-02 00:20:31,10 2019-01-02 19:34:33,10
2019-01-02 00:20:36,10 2019-01-02 19:34:38,10
2019-01-02 00:20:41,10 2019-01-02 19:34:44,10
2019-01-02 00:20:46,10 2019-01-02 19:34:49,10
2019-01-02 00:20:51,10 2019-01-02 19:34:54,10
2019-01-02 00:20:56,10 2019-01-02 19:34:59,10
2019-01-02 00:21:01,10 2019-01-02 19:35:04,10
2019-01-02 00:21:06,10 2019-01-02 19:35:09,10
2019-01-02 00:21:11,10 2019-01-02 19:35:14,10
2019-01-02 00:21:16,10 2019-01-02 19:35:19,10
2019-01-02 00:21:21,10 2019-01-02 19:35:24,10
2019-01-02 00:21:26,10 2019-01-02 19:35:29,10
2019-01-02 00:21:31,10 2019-01-02 19:35:34,10
2019-01-02 00:21:36,10 2019-01-02 19:35:39,10
2019-01-02 00:21:41,10 2019-01-02 19:35:44,10
2019-01-02 00:21:46,10 2019-01-02 19:35:49,10
2019-01-02 00:21:51,10 2019-01-02 19:35:54,10
2019-01-02 00:21:56,10 2019-01-02 19:35:59,10

View file

@ -1,86 +1,86 @@
2019-01-02 00:07:03,10 2019-01-02 19:21:17,10
2019-01-02 00:07:08,10 2019-01-02 19:21:22,10
2019-01-02 00:07:13,10 2019-01-02 19:21:27,10
2019-01-02 00:07:18,10 2019-01-02 19:21:32,10
2019-01-02 00:07:23,10 2019-01-02 19:21:37,10
2019-01-02 00:07:28,10 2019-01-02 19:21:42,10
2019-01-02 00:07:33,10 2019-01-02 19:21:47,10
2019-01-02 00:07:38,10 2019-01-02 19:21:52,10
2019-01-02 00:07:43,10 2019-01-02 19:21:57,10
2019-01-02 00:07:48,10 2019-01-02 19:22:02,10
2019-01-02 00:07:53,10 2019-01-02 19:22:07,10
2019-01-02 00:07:58,10 2019-01-02 19:22:12,10
2019-01-02 00:08:03,10 2019-01-02 19:22:19,10
2019-01-02 00:08:08,10 2019-01-02 19:22:24,10
2019-01-02 00:08:13,10 2019-01-02 19:22:29,10
2019-01-02 00:08:18,10 2019-01-02 19:22:34,10
2019-01-02 00:08:23,10 2019-01-02 19:22:39,10
2019-01-02 00:08:28,10 2019-01-02 19:22:44,10
2019-01-02 00:08:33,10 2019-01-02 19:22:49,10
2019-01-02 00:08:38,10 2019-01-02 19:22:54,10
2019-01-02 00:08:43,10 2019-01-02 19:22:59,10
2019-01-02 00:08:48,10 2019-01-02 19:23:04,10
2019-01-02 00:08:53,10 2019-01-02 19:23:09,10
2019-01-02 00:08:58,10 2019-01-02 19:23:14,10
2019-01-02 00:09:03,10 2019-01-02 19:23:19,10
2019-01-02 00:09:08,10 2019-01-02 19:23:24,10
2019-01-02 00:09:13,10 2019-01-02 19:23:29,10
2019-01-02 00:09:18,10 2019-01-02 19:23:34,10
2019-01-02 00:09:23,10 2019-01-02 19:23:39,10
2019-01-02 00:09:28,10 2019-01-02 19:23:44,10
2019-01-02 00:09:33,10 2019-01-02 19:23:49,10
2019-01-02 00:09:38,10 2019-01-02 19:23:54,10
2019-01-02 00:09:43,10 2019-01-02 19:24:05,10
2019-01-02 00:09:48,10 2019-01-02 19:24:10,10
2019-01-02 00:09:53,10 2019-01-02 19:24:15,10
2019-01-02 00:09:58,10 2019-01-02 19:24:20,10
2019-01-02 00:10:03,10 2019-01-02 19:24:25,10
2019-01-02 00:10:08,10 2019-01-02 19:24:30,10
2019-01-02 00:10:13,10 2019-01-02 19:24:35,10
2019-01-02 00:10:18,10 2019-01-02 19:24:40,10
2019-01-02 00:10:23,10 2019-01-02 19:24:45,10
2019-01-02 00:10:28,10 2019-01-02 19:24:50,10
2019-01-02 00:10:33,10 2019-01-02 19:24:55,10
2019-01-02 00:10:38,10 2019-01-02 19:25:00,10
2019-01-02 00:10:43,10 2019-01-02 19:25:05,10
2019-01-02 00:10:48,10 2019-01-02 19:25:10,10
2019-01-02 00:10:53,10 2019-01-02 19:25:15,10
2019-01-02 00:10:58,10 2019-01-02 19:25:20,10
2019-01-02 00:11:03,10 2019-01-02 19:25:25,10
2019-01-02 00:11:08,10 2019-01-02 19:25:30,10
2019-01-02 00:11:13,10 2019-01-02 19:25:35,10
2019-01-02 00:11:18,10 2019-01-02 19:25:40,10
2019-01-02 00:11:23,10 2019-01-02 19:25:45,10
2019-01-02 00:11:28,10 2019-01-02 19:25:50,10
2019-01-02 00:11:33,10 2019-01-02 19:25:55,10
2019-01-02 00:11:38,10 2019-01-02 19:26:00,10
2019-01-02 00:11:43,10 2019-01-02 19:26:05,10
2019-01-02 00:11:48,10 2019-01-02 19:26:10,10
2019-01-02 00:11:53,10 2019-01-02 19:26:15,10
2019-01-02 00:11:58,10 2019-01-02 19:26:20,10
2019-01-02 00:12:03,10 2019-01-02 19:26:25,10
2019-01-02 00:12:08,10 2019-01-02 19:26:30,10
2019-01-02 00:12:13,10 2019-01-02 19:26:35,10
2019-01-02 00:12:18,10 2019-01-02 19:26:40,10
2019-01-02 00:12:23,10 2019-01-02 19:26:45,10
2019-01-02 00:12:28,10 2019-01-02 19:26:50,10
2019-01-02 00:12:33,10 2019-01-02 19:26:55,10
2019-01-02 00:12:38,10 2019-01-02 19:27:00,10
2019-01-02 00:12:43,10 2019-01-02 19:27:05,10
2019-01-02 00:12:48,10 2019-01-02 19:27:10,10
2019-01-02 00:12:53,10 2019-01-02 19:27:15,10
2019-01-02 00:12:58,10 2019-01-02 19:27:20,10
2019-01-02 00:13:03,10 2019-01-02 19:27:25,10
2019-01-02 00:13:08,10 2019-01-02 19:27:30,10
2019-01-02 00:13:13,10 2019-01-02 19:27:35,10
2019-01-02 00:13:18,10 2019-01-02 19:27:40,10
2019-01-02 00:13:23,10 2019-01-02 19:27:45,10
2019-01-02 00:13:28,10 2019-01-02 19:27:50,10
2019-01-02 00:13:33,10 2019-01-02 19:27:55,10
2019-01-02 00:13:38,10 2019-01-02 19:28:00,10
2019-01-02 00:13:43,10 2019-01-02 19:28:05,10
2019-01-02 00:13:48,10 2019-01-02 19:28:10,10
2019-01-02 00:13:53,10 2019-01-02 19:28:15,10
2019-01-02 00:14:19,10 2019-01-02 19:28:20,10
2019-01-02 00:14:24,10 2019-01-02 19:28:25,10
2019-01-02 00:14:31,10 2019-01-02 19:28:30,10

View file

@ -1,86 +1,86 @@
2019-01-01 23:59:47,10 2019-01-02 19:14:06,10
2019-01-01 23:59:52,10 2019-01-02 19:14:11,10
2019-01-01 23:59:57,10 2019-01-02 19:14:16,10
2019-01-02 00:00:02,10 2019-01-02 19:14:21,10
2019-01-02 00:00:07,10 2019-01-02 19:14:26,10
2019-01-02 00:00:12,10 2019-01-02 19:14:32,10
2019-01-02 00:00:17,10 2019-01-02 19:14:37,10
2019-01-02 00:00:22,10 2019-01-02 19:14:42,10
2019-01-02 00:00:27,10 2019-01-02 19:14:47,10
2019-01-02 00:00:32,10 2019-01-02 19:14:52,10
2019-01-02 00:00:37,10 2019-01-02 19:14:57,10
2019-01-02 00:00:42,10 2019-01-02 19:15:02,10
2019-01-02 00:00:47,10 2019-01-02 19:15:07,10
2019-01-02 00:00:52,10 2019-01-02 19:15:12,10
2019-01-02 00:00:57,10 2019-01-02 19:15:17,10
2019-01-02 00:01:02,10 2019-01-02 19:15:22,10
2019-01-02 00:01:07,10 2019-01-02 19:15:27,10
2019-01-02 00:01:12,10 2019-01-02 19:15:32,10
2019-01-02 00:01:17,10 2019-01-02 19:15:37,10
2019-01-02 00:01:28,10 2019-01-02 19:15:42,10
2019-01-02 00:01:33,10 2019-01-02 19:15:47,10
2019-01-02 00:01:38,10 2019-01-02 19:15:52,10
2019-01-02 00:01:43,10 2019-01-02 19:15:57,10
2019-01-02 00:01:48,10 2019-01-02 19:16:02,10
2019-01-02 00:01:53,10 2019-01-02 19:16:07,10
2019-01-02 00:01:58,10 2019-01-02 19:16:12,10
2019-01-02 00:02:03,10 2019-01-02 19:16:17,10
2019-01-02 00:02:08,10 2019-01-02 19:16:22,10
2019-01-02 00:02:13,10 2019-01-02 19:16:27,10
2019-01-02 00:02:18,10 2019-01-02 19:16:32,10
2019-01-02 00:02:23,10 2019-01-02 19:16:37,10
2019-01-02 00:02:28,10 2019-01-02 19:16:42,10
2019-01-02 00:02:33,10 2019-01-02 19:16:47,10
2019-01-02 00:02:38,10 2019-01-02 19:16:52,10
2019-01-02 00:02:43,10 2019-01-02 19:16:57,10
2019-01-02 00:02:48,10 2019-01-02 19:17:02,10
2019-01-02 00:02:53,10 2019-01-02 19:17:07,10
2019-01-02 00:02:58,10 2019-01-02 19:17:12,10
2019-01-02 00:03:03,10 2019-01-02 19:17:17,10
2019-01-02 00:03:08,10 2019-01-02 19:17:22,10
2019-01-02 00:03:13,10 2019-01-02 19:17:27,10
2019-01-02 00:03:18,10 2019-01-02 19:17:32,10
2019-01-02 00:03:23,10 2019-01-02 19:17:37,10
2019-01-02 00:03:28,10 2019-01-02 19:17:42,10
2019-01-02 00:03:33,10 2019-01-02 19:17:47,10
2019-01-02 00:03:38,10 2019-01-02 19:17:52,10
2019-01-02 00:03:43,10 2019-01-02 19:17:57,10
2019-01-02 00:03:48,10 2019-01-02 19:18:02,10
2019-01-02 00:03:53,10 2019-01-02 19:18:07,10
2019-01-02 00:03:58,10 2019-01-02 19:18:12,10
2019-01-02 00:04:03,10 2019-01-02 19:18:17,10
2019-01-02 00:04:08,10 2019-01-02 19:18:22,10
2019-01-02 00:04:13,10 2019-01-02 19:18:27,10
2019-01-02 00:04:18,10 2019-01-02 19:18:32,10
2019-01-02 00:04:23,10 2019-01-02 19:18:37,10
2019-01-02 00:04:28,10 2019-01-02 19:18:42,10
2019-01-02 00:04:33,10 2019-01-02 19:18:47,10
2019-01-02 00:04:38,10 2019-01-02 19:18:52,10
2019-01-02 00:04:43,10 2019-01-02 19:18:57,10
2019-01-02 00:04:48,10 2019-01-02 19:19:02,10
2019-01-02 00:04:53,10 2019-01-02 19:19:07,10
2019-01-02 00:04:58,10 2019-01-02 19:19:12,10
2019-01-02 00:05:03,10 2019-01-02 19:19:17,10
2019-01-02 00:05:08,10 2019-01-02 19:19:22,10
2019-01-02 00:05:13,10 2019-01-02 19:19:27,10
2019-01-02 00:05:18,10 2019-01-02 19:19:32,10
2019-01-02 00:05:23,10 2019-01-02 19:19:37,10
2019-01-02 00:05:28,10 2019-01-02 19:19:42,10
2019-01-02 00:05:33,10 2019-01-02 19:19:47,10
2019-01-02 00:05:38,10 2019-01-02 19:19:52,10
2019-01-02 00:05:43,10 2019-01-02 19:19:57,10
2019-01-02 00:05:48,10 2019-01-02 19:20:02,10
2019-01-02 00:05:53,10 2019-01-02 19:20:07,10
2019-01-02 00:05:58,10 2019-01-02 19:20:12,10
2019-01-02 00:06:03,10 2019-01-02 19:20:17,10
2019-01-02 00:06:08,10 2019-01-02 19:20:22,10
2019-01-02 00:06:13,10 2019-01-02 19:20:27,10
2019-01-02 00:06:18,10 2019-01-02 19:20:32,10
2019-01-02 00:06:23,10 2019-01-02 19:20:37,10
2019-01-02 00:06:28,10 2019-01-02 19:20:42,10
2019-01-02 00:06:33,10 2019-01-02 19:20:47,10
2019-01-02 00:06:38,10 2019-01-02 19:20:52,10
2019-01-02 00:06:43,10 2019-01-02 19:20:57,10
2019-01-02 00:06:48,10 2019-01-02 19:21:02,10
2019-01-02 00:06:53,10 2019-01-02 19:21:07,10
2019-01-02 00:06:58,10 2019-01-02 19:21:12,10

View file

@ -1,86 +1,86 @@
2019-01-01 23:50:48,10 2019-01-02 19:02:41,10
2019-01-01 23:50:53,10 2019-01-02 19:02:46,10
2019-01-01 23:51:03,10 2019-01-02 19:02:51,10
2019-01-01 23:51:08,10 2019-01-02 19:02:56,10
2019-01-01 23:51:13,10 2019-01-02 19:03:01,10
2019-01-01 23:51:18,10 2019-01-02 19:03:06,10
2019-01-01 23:51:23,10 2019-01-02 19:03:11,10
2019-01-01 23:51:28,10 2019-01-02 19:03:16,10
2019-01-01 23:51:33,10 2019-01-02 19:03:21,10
2019-01-01 23:51:38,10 2019-01-02 19:03:33,10
2019-01-01 23:51:49,10 2019-01-02 19:03:33,10
2019-01-01 23:51:54,10 2019-01-02 19:03:33,10
2019-01-01 23:51:59,10 2019-01-02 19:03:33,10
2019-01-01 23:52:04,10 2019-01-02 19:03:33,10
2019-01-01 23:52:09,10 2019-01-02 19:03:33,10
2019-01-01 23:52:14,10 2019-01-02 19:03:33,10
2019-01-01 23:52:19,10 2019-01-02 19:03:33,10
2019-01-01 23:52:24,10 2019-01-02 19:03:33,10
2019-01-01 23:52:29,10 2019-01-02 19:03:33,10
2019-01-01 23:52:34,10 2019-01-02 19:03:33,10
2019-01-01 23:52:39,10 2019-01-02 19:08:33,10
2019-01-01 23:52:44,10 2019-01-02 19:08:38,10
2019-01-01 23:52:49,10 2019-01-02 19:08:43,10
2019-01-01 23:52:54,10 2019-01-02 19:08:48,10
2019-01-01 23:52:59,10 2019-01-02 19:08:53,10
2019-01-01 23:53:04,10 2019-01-02 19:08:58,10
2019-01-01 23:53:09,10 2019-01-02 19:09:03,10
2019-01-01 23:53:14,10 2019-01-02 19:09:08,10
2019-01-01 23:53:19,10 2019-01-02 19:09:16,10
2019-01-01 23:53:24,10 2019-01-02 19:09:21,10
2019-01-01 23:53:29,10 2019-01-02 19:09:26,10
2019-01-01 23:53:34,10 2019-01-02 19:09:31,10
2019-01-01 23:53:39,10 2019-01-02 19:09:36,10
2019-01-01 23:53:44,10 2019-01-02 19:09:41,10
2019-01-01 23:53:49,10 2019-01-02 19:09:46,10
2019-01-01 23:53:54,10 2019-01-02 19:09:51,10
2019-01-01 23:53:59,10 2019-01-02 19:09:56,10
2019-01-01 23:54:04,10 2019-01-02 19:10:01,10
2019-01-01 23:54:09,10 2019-01-02 19:10:06,10
2019-01-01 23:54:14,10 2019-01-02 19:10:11,10
2019-01-01 23:54:19,10 2019-01-02 19:10:16,10
2019-01-01 23:54:24,10 2019-01-02 19:10:21,10
2019-01-01 23:54:34,10 2019-01-02 19:10:26,10
2019-01-01 23:54:39,10 2019-01-02 19:10:31,10
2019-01-01 23:54:44,10 2019-01-02 19:10:36,10
2019-01-01 23:54:49,10 2019-01-02 19:10:41,10
2019-01-01 23:54:54,10 2019-01-02 19:10:46,10
2019-01-01 23:54:59,10 2019-01-02 19:10:51,10
2019-01-01 23:56:32,10 2019-01-02 19:10:56,10
2019-01-01 23:56:37,10 2019-01-02 19:11:01,10
2019-01-01 23:56:42,10 2019-01-02 19:11:06,10
2019-01-01 23:56:47,10 2019-01-02 19:11:11,10
2019-01-01 23:56:52,10 2019-01-02 19:11:16,10
2019-01-01 23:56:57,10 2019-01-02 19:11:21,10
2019-01-01 23:57:02,10 2019-01-02 19:11:26,10
2019-01-01 23:57:07,10 2019-01-02 19:11:31,10
2019-01-01 23:57:12,10 2019-01-02 19:11:36,10
2019-01-01 23:57:17,10 2019-01-02 19:11:41,10
2019-01-01 23:57:22,10 2019-01-02 19:11:46,10
2019-01-01 23:57:27,10 2019-01-02 19:11:51,10
2019-01-01 23:57:32,10 2019-01-02 19:11:56,10
2019-01-01 23:57:37,10 2019-01-02 19:12:01,10
2019-01-01 23:57:42,10 2019-01-02 19:12:06,10
2019-01-01 23:57:47,10 2019-01-02 19:12:11,10
2019-01-01 23:57:53,10 2019-01-02 19:12:16,10
2019-01-01 23:57:58,10 2019-01-02 19:12:21,10
2019-01-01 23:58:03,10 2019-01-02 19:12:26,10
2019-01-01 23:58:12,10 2019-01-02 19:12:31,10
2019-01-01 23:58:17,10 2019-01-02 19:12:36,10
2019-01-01 23:58:22,10 2019-01-02 19:12:41,10
2019-01-01 23:58:27,10 2019-01-02 19:12:46,10
2019-01-01 23:58:32,10 2019-01-02 19:12:51,10
2019-01-01 23:58:37,10 2019-01-02 19:12:56,10
2019-01-01 23:58:42,10 2019-01-02 19:13:01,10
2019-01-01 23:58:47,10 2019-01-02 19:13:06,10
2019-01-01 23:58:52,10 2019-01-02 19:13:11,10
2019-01-01 23:58:57,10 2019-01-02 19:13:16,10
2019-01-01 23:59:02,10 2019-01-02 19:13:21,10
2019-01-01 23:59:07,10 2019-01-02 19:13:26,10
2019-01-01 23:59:12,10 2019-01-02 19:13:31,10
2019-01-01 23:59:17,10 2019-01-02 19:13:36,10
2019-01-01 23:59:22,10 2019-01-02 19:13:41,10
2019-01-01 23:59:27,10 2019-01-02 19:13:46,10
2019-01-01 23:59:32,10 2019-01-02 19:13:51,10
2019-01-01 23:59:37,10 2019-01-02 19:13:56,10
2019-01-01 23:59:42,10 2019-01-02 19:14:01,10

View file

@ -1,86 +1,86 @@
2019-01-01 23:43:05,10 2019-01-02 18:51:48,10
2019-01-01 23:43:10,10 2019-01-02 18:51:53,10
2019-01-01 23:43:15,10 2019-01-02 18:51:53,10
2019-01-01 23:43:20,10 2019-01-02 18:51:53,10
2019-01-01 23:43:25,10 2019-01-02 18:51:53,10
2019-01-01 23:43:30,10 2019-01-02 18:51:58,10
2019-01-01 23:43:35,10 2019-01-02 18:52:03,10
2019-01-01 23:43:40,10 2019-01-02 18:52:08,10
2019-01-01 23:43:45,10 2019-01-02 18:52:13,10
2019-01-01 23:43:50,10 2019-01-02 18:52:18,10
2019-01-01 23:43:55,10 2019-01-02 18:52:23,10
2019-01-01 23:44:02,10 2019-01-02 18:52:28,10
2019-01-01 23:44:07,10 2019-01-02 18:52:33,10
2019-01-01 23:44:12,10 2019-01-02 18:52:38,10
2019-01-01 23:44:17,10 2019-01-02 18:52:43,10
2019-01-01 23:44:22,10 2019-01-02 18:52:48,10
2019-01-01 23:44:27,10 2019-01-02 18:52:53,10
2019-01-01 23:44:32,10 2019-01-02 18:52:58,10
2019-01-01 23:44:37,10 2019-01-02 18:53:03,10
2019-01-01 23:44:42,10 2019-01-02 18:53:08,10
2019-01-01 23:44:47,10 2019-01-02 18:53:13,10
2019-01-01 23:44:52,10 2019-01-02 18:53:13,10
2019-01-01 23:44:57,10 2019-01-02 18:53:13,10
2019-01-01 23:45:02,10 2019-01-02 18:53:13,10
2019-01-01 23:45:11,10 2019-01-02 18:53:13,10
2019-01-01 23:45:16,10 2019-01-02 18:53:13,10
2019-01-01 23:45:21,10 2019-01-02 18:53:13,10
2019-01-01 23:45:26,10 2019-01-02 18:53:13,10
2019-01-01 23:45:31,10 2019-01-02 18:53:13,10
2019-01-01 23:45:36,10 2019-01-02 18:53:13,10
2019-01-01 23:45:41,10 2019-01-02 18:53:13,10
2019-01-01 23:45:46,10 2019-01-02 18:53:13,10
2019-01-01 23:45:51,10 2019-01-02 18:53:22,10
2019-01-01 23:45:56,10 2019-01-02 18:53:27,10
2019-01-01 23:46:01,10 2019-01-02 18:53:32,10
2019-01-01 23:46:06,10 2019-01-02 18:53:37,10
2019-01-01 23:46:11,10 2019-01-02 18:53:42,10
2019-01-01 23:46:16,10 2019-01-02 18:53:47,10
2019-01-01 23:46:21,10 2019-01-02 18:53:52,10
2019-01-01 23:46:26,10 2019-01-02 18:53:57,10
2019-01-01 23:46:31,10 2019-01-02 18:54:02,10
2019-01-01 23:46:36,10 2019-01-02 18:54:07,10
2019-01-01 23:46:41,10 2019-01-02 18:54:12,10
2019-01-01 23:46:46,10 2019-01-02 18:54:17,10
2019-01-01 23:46:51,10 2019-01-02 18:54:22,10
2019-01-01 23:46:56,10 2019-01-02 18:54:27,10
2019-01-01 23:47:01,10 2019-01-02 18:54:32,10
2019-01-01 23:47:06,10 2019-01-02 18:54:37,10
2019-01-01 23:47:11,10 2019-01-02 18:54:42,10
2019-01-01 23:47:16,10 2019-01-02 18:54:47,10
2019-01-01 23:47:21,10 2019-01-02 18:54:52,10
2019-01-01 23:47:26,10 2019-01-02 18:54:57,10
2019-01-01 23:47:31,10 2019-01-02 18:55:02,10
2019-01-01 23:47:36,10 2019-01-02 18:55:07,10
2019-01-01 23:47:41,10 2019-01-02 18:55:12,10
2019-01-01 23:47:46,10 2019-01-02 18:55:17,10
2019-01-01 23:47:51,10 2019-01-02 18:55:22,10
2019-01-01 23:47:56,10 2019-01-02 18:55:27,10
2019-01-01 23:48:01,10 2019-01-02 18:55:32,10
2019-01-01 23:48:06,10 2019-01-02 18:55:37,10
2019-01-01 23:48:11,10 2019-01-02 18:55:42,10
2019-01-01 23:48:16,10 2019-01-02 18:55:47,10
2019-01-01 23:48:21,10 2019-01-02 18:55:52,10
2019-01-01 23:48:26,10 2019-01-02 18:55:57,10
2019-01-01 23:48:31,10 2019-01-02 18:56:02,10
2019-01-01 23:48:36,10 2019-01-02 18:56:07,10
2019-01-01 23:48:41,10 2019-01-02 18:56:12,10
2019-01-01 23:48:46,10 2019-01-02 18:56:17,10
2019-01-01 23:48:51,10 2019-01-02 18:56:22,10
2019-01-01 23:48:56,10 2019-01-02 18:56:27,10
2019-01-01 23:49:01,10 2019-01-02 18:56:32,10
2019-01-01 23:49:21,10 2019-01-02 18:56:37,10
2019-01-01 23:49:26,10 2019-01-02 18:56:42,10
2019-01-01 23:49:31,10 2019-01-02 18:56:47,10
2019-01-01 23:49:36,10 2019-01-02 18:56:52,10
2019-01-01 23:49:41,10 2019-01-02 18:56:57,10
2019-01-01 23:49:46,10 2019-01-02 18:57:02,10
2019-01-01 23:49:51,10 2019-01-02 18:57:07,10
2019-01-01 23:49:56,10 2019-01-02 18:57:12,10
2019-01-01 23:50:01,10 2019-01-02 18:57:17,10
2019-01-01 23:50:06,10 2019-01-02 18:57:22,10
2019-01-01 23:50:11,10 2019-01-02 18:57:27,10
2019-01-01 23:50:16,10 2019-01-02 18:57:32,10
2019-01-01 23:50:21,10 2019-01-02 18:57:37,10
2019-01-01 23:50:26,10 2019-01-02 19:02:31,10
2019-01-01 23:50:43,10 2019-01-02 19:02:36,10

View file

@ -1,86 +1,9 @@
2019-01-01 23:27:07,10 2019-01-02 18:51:43,10
2019-01-01 23:27:12,10 2019-01-02 18:51:53,10
2019-01-01 23:27:17,10 2019-01-02 18:51:53,10
2019-01-01 23:27:22,10 2019-01-02 18:51:53,10
2019-01-01 23:27:27,10 2019-01-02 18:51:53,10
2019-01-01 23:27:32,10 2019-01-02 18:51:53,10
2019-01-01 23:27:37,10 2019-01-02 18:51:53,10
2019-01-01 23:27:42,10 2019-01-02 18:51:53,10
2019-01-01 23:27:47,10 2019-01-02 18:51:53,10
2019-01-01 23:27:52,10
2019-01-01 23:27:57,10
2019-01-01 23:28:02,10
2019-01-01 23:28:07,10
2019-01-01 23:28:12,10
2019-01-01 23:28:17,10
2019-01-01 23:28:22,10
2019-01-01 23:28:27,10
2019-01-01 23:28:32,10
2019-01-01 23:28:37,10
2019-01-01 23:28:42,10
2019-01-01 23:28:47,10
2019-01-01 23:28:52,10
2019-01-01 23:28:57,10
2019-01-01 23:29:02,10
2019-01-01 23:29:07,10
2019-01-01 23:29:12,10
2019-01-01 23:29:17,10
2019-01-01 23:29:22,10
2019-01-01 23:29:27,10
2019-01-01 23:29:32,10
2019-01-01 23:29:37,10
2019-01-01 23:29:42,10
2019-01-01 23:29:47,10
2019-01-01 23:29:52,10
2019-01-01 23:29:57,10
2019-01-01 23:30:02,10
2019-01-01 23:35:55,10
2019-01-01 23:36:00,10
2019-01-01 23:36:05,10
2019-01-01 23:36:10,10
2019-01-01 23:36:15,10
2019-01-01 23:36:20,10
2019-01-01 23:36:25,10
2019-01-01 23:36:30,10
2019-01-01 23:36:35,10
2019-01-01 23:36:40,10
2019-01-01 23:36:45,10
2019-01-01 23:36:50,10
2019-01-01 23:36:55,10
2019-01-01 23:37:02,10
2019-01-01 23:37:07,10
2019-01-01 23:37:12,10
2019-01-01 23:37:17,10
2019-01-01 23:37:22,10
2019-01-01 23:39:27,10
2019-01-01 23:39:32,10
2019-01-01 23:39:37,10
2019-01-01 23:39:42,10
2019-01-01 23:39:47,10
2019-01-01 23:40:44,10
2019-01-01 23:40:49,10
2019-01-01 23:40:54,10
2019-01-01 23:40:59,10
2019-01-01 23:41:04,10
2019-01-01 23:41:09,10
2019-01-01 23:41:14,10
2019-01-01 23:41:19,10
2019-01-01 23:41:24,10
2019-01-01 23:41:29,10
2019-01-01 23:41:34,10
2019-01-01 23:41:39,10
2019-01-01 23:41:44,10
2019-01-01 23:41:49,10
2019-01-01 23:41:54,10
2019-01-01 23:41:59,10
2019-01-01 23:42:04,10
2019-01-01 23:42:09,10
2019-01-01 23:42:14,10
2019-01-01 23:42:19,10
2019-01-01 23:42:24,10
2019-01-01 23:42:29,10
2019-01-01 23:42:34,10
2019-01-01 23:42:39,10
2019-01-01 23:42:44,10
2019-01-01 23:42:49,10
2019-01-01 23:42:54,10

View file

@ -1,16 +1,23 @@
2019-01-01 16:29:39,10 2019-01-02 18:49:55,10
2019-01-01 16:29:40,10 2019-01-02 18:49:56,10
2019-01-01 16:29:41,10 2019-01-02 18:49:57,10
2019-01-01 16:29:42,10 2019-01-02 18:51:25,10
2019-01-01 16:31:21,10 2019-01-02 18:51:26,10
2019-01-01 16:31:22,10 2019-01-02 18:51:27,10
2019-01-01 16:31:23,10 2019-01-02 18:51:28,10
2019-01-01 16:31:24,10 2019-01-02 18:51:40,10
2019-01-01 16:49:40,10 2019-01-02 18:51:41,10
2019-01-01 16:49:41,10 2019-01-02 18:51:42,10
2019-01-01 16:49:42,10 2019-01-02 18:51:43,10
2019-01-01 16:49:43,10 2019-01-02 18:51:49,10
2019-01-01 16:51:23,10 2019-01-02 18:51:50,10
2019-01-01 16:51:24,10 2019-01-02 18:51:51,10
2019-01-01 16:51:25,10 2019-01-02 18:51:52,10
2019-01-01 16:51:26,10 2019-01-02 18:53:09,10
2019-01-02 18:53:10,10
2019-01-02 18:53:11,10
2019-01-02 18:53:12,10
2019-01-02 19:03:29,10
2019-01-02 19:03:30,10
2019-01-02 19:03:31,10
2019-01-02 19:03:32,10

View file

@ -0,0 +1,86 @@
2019-01-02 17:05:13,10
2019-01-02 17:05:14,10
2019-01-02 17:05:15,10
2019-01-02 18:02:23,10
2019-01-02 18:02:24,10
2019-01-02 18:02:25,10
2019-01-02 18:02:26,10
2019-01-02 18:21:31,10
2019-01-02 18:21:32,10
2019-01-02 18:21:33,10
2019-01-02 18:21:34,10
2019-01-02 18:21:47,10
2019-01-02 18:21:48,10
2019-01-02 18:21:49,10
2019-01-02 18:21:50,10
2019-01-02 18:21:51,10
2019-01-02 18:29:16,10
2019-01-02 18:29:17,10
2019-01-02 18:29:18,10
2019-01-02 18:29:19,10
2019-01-02 18:31:37,10
2019-01-02 18:31:38,10
2019-01-02 18:31:39,10
2019-01-02 18:31:40,10
2019-01-02 18:32:06,10
2019-01-02 18:32:07,10
2019-01-02 18:32:08,10
2019-01-02 18:32:09,10
2019-01-02 18:32:59,10
2019-01-02 18:33:00,10
2019-01-02 18:33:01,10
2019-01-02 18:33:02,10
2019-01-02 18:33:33,10
2019-01-02 18:33:34,10
2019-01-02 18:33:35,10
2019-01-02 18:33:36,10
2019-01-02 18:33:37,10
2019-01-02 18:34:07,10
2019-01-02 18:34:08,10
2019-01-02 18:34:09,10
2019-01-02 18:34:10,10
2019-01-02 18:37:59,10
2019-01-02 18:38:00,10
2019-01-02 18:38:01,10
2019-01-02 18:38:02,10
2019-01-02 18:38:48,10
2019-01-02 18:38:49,10
2019-01-02 18:38:50,10
2019-01-02 18:38:51,10
2019-01-02 18:38:52,10
2019-01-02 18:40:45,10
2019-01-02 18:40:46,10
2019-01-02 18:40:47,10
2019-01-02 18:40:48,10
2019-01-02 18:40:56,10
2019-01-02 18:40:57,10
2019-01-02 18:40:58,10
2019-01-02 18:40:59,10
2019-01-02 18:41:00,10
2019-01-02 18:41:50,10
2019-01-02 18:41:51,10
2019-01-02 18:41:52,10
2019-01-02 18:41:53,10
2019-01-02 18:43:39,10
2019-01-02 18:43:40,10
2019-01-02 18:43:41,10
2019-01-02 18:43:42,10
2019-01-02 18:44:37,10
2019-01-02 18:44:38,10
2019-01-02 18:44:39,10
2019-01-02 18:44:40,10
2019-01-02 18:44:41,10
2019-01-02 18:45:17,10
2019-01-02 18:45:18,10
2019-01-02 18:45:19,10
2019-01-02 18:45:20,10
2019-01-02 18:47:19,10
2019-01-02 18:47:20,10
2019-01-02 18:47:21,10
2019-01-02 18:47:22,10
2019-01-02 18:47:23,10
2019-01-02 18:49:03,10
2019-01-02 18:49:05,10
2019-01-02 18:49:06,10
2019-01-02 18:49:07,10
2019-01-02 18:49:54,10

View file

@ -0,0 +1,86 @@
2019-01-02 11:15:04,10
2019-01-02 11:16:21,10
2019-01-02 11:16:22,10
2019-01-02 11:16:23,10
2019-01-02 11:16:24,10
2019-01-02 11:16:25,10
2019-01-02 11:18:51,10
2019-01-02 11:18:52,10
2019-01-02 11:18:53,10
2019-01-02 11:18:54,10
2019-01-02 16:19:57,10
2019-01-02 16:19:58,10
2019-01-02 16:19:59,10
2019-01-02 16:20:00,10
2019-01-02 16:20:01,10
2019-01-02 16:21:08,10
2019-01-02 16:21:09,10
2019-01-02 16:21:10,10
2019-01-02 16:21:11,10
2019-01-02 16:21:25,10
2019-01-02 16:21:26,10
2019-01-02 16:21:27,10
2019-01-02 16:21:28,10
2019-01-02 16:22:24,10
2019-01-02 16:22:25,10
2019-01-02 16:22:26,10
2019-01-02 16:22:27,10
2019-01-02 16:23:42,10
2019-01-02 16:23:43,10
2019-01-02 16:23:44,10
2019-01-02 16:23:45,10
2019-01-02 16:23:46,10
2019-01-02 16:24:55,10
2019-01-02 16:24:56,10
2019-01-02 16:24:57,10
2019-01-02 16:24:58,10
2019-01-02 16:24:59,10
2019-01-02 16:25:20,10
2019-01-02 16:25:21,10
2019-01-02 16:25:22,10
2019-01-02 16:25:23,10
2019-01-02 16:25:24,10
2019-01-02 16:26:25,10
2019-01-02 16:26:26,10
2019-01-02 16:26:27,10
2019-01-02 16:26:28,10
2019-01-02 16:52:03,10
2019-01-02 16:52:04,10
2019-01-02 16:52:05,10
2019-01-02 16:52:06,10
2019-01-02 16:52:07,10
2019-01-02 16:52:47,10
2019-01-02 16:52:48,10
2019-01-02 16:52:49,10
2019-01-02 16:52:50,10
2019-01-02 16:53:19,10
2019-01-02 16:53:20,10
2019-01-02 16:53:22,10
2019-01-02 16:53:23,10
2019-01-02 16:53:46,10
2019-01-02 16:53:47,10
2019-01-02 16:53:48,10
2019-01-02 16:53:49,10
2019-01-02 17:00:57,10
2019-01-02 17:00:58,10
2019-01-02 17:00:59,10
2019-01-02 17:01:00,10
2019-01-02 17:01:06,10
2019-01-02 17:01:07,10
2019-01-02 17:01:08,10
2019-01-02 17:01:09,10
2019-01-02 17:02:14,10
2019-01-02 17:02:15,10
2019-01-02 17:02:16,10
2019-01-02 17:02:17,10
2019-01-02 17:02:18,10
2019-01-02 17:02:34,10
2019-01-02 17:02:35,10
2019-01-02 17:02:36,10
2019-01-02 17:02:37,10
2019-01-02 17:02:38,10
2019-01-02 17:02:48,10
2019-01-02 17:02:49,10
2019-01-02 17:02:50,10
2019-01-02 17:02:51,10
2019-01-02 17:05:12,10

View file

@ -0,0 +1,86 @@
2019-01-01 16:29:39,10
2019-01-01 16:29:40,10
2019-01-01 16:29:41,10
2019-01-01 16:29:42,10
2019-01-01 16:31:21,10
2019-01-01 16:31:22,10
2019-01-01 16:31:23,10
2019-01-01 16:31:24,10
2019-01-01 16:49:40,10
2019-01-01 16:49:41,10
2019-01-01 16:49:42,10
2019-01-01 16:49:43,10
2019-01-01 16:51:23,10
2019-01-01 16:51:24,10
2019-01-01 16:51:25,10
2019-01-01 16:51:26,10
2019-01-02 10:46:44,10
2019-01-02 10:46:45,10
2019-01-02 10:46:46,10
2019-01-02 10:46:47,10
2019-01-02 10:46:48,10
2019-01-02 10:48:16,10
2019-01-02 10:48:17,10
2019-01-02 10:48:18,10
2019-01-02 10:48:19,10
2019-01-02 10:48:41,10
2019-01-02 10:48:42,10
2019-01-02 10:48:43,10
2019-01-02 10:48:44,10
2019-01-02 10:48:45,10
2019-01-02 10:49:30,10
2019-01-02 10:49:31,10
2019-01-02 10:49:32,10
2019-01-02 10:49:33,10
2019-01-02 10:49:51,10
2019-01-02 10:49:52,10
2019-01-02 10:49:53,10
2019-01-02 10:49:54,10
2019-01-02 10:56:09,10
2019-01-02 10:56:10,10
2019-01-02 10:56:11,10
2019-01-02 10:56:12,10
2019-01-02 10:56:35,10
2019-01-02 10:56:36,10
2019-01-02 10:56:37,10
2019-01-02 10:56:38,10
2019-01-02 11:01:55,10
2019-01-02 11:01:56,10
2019-01-02 11:01:57,10
2019-01-02 11:01:58,10
2019-01-02 11:03:23,10
2019-01-02 11:03:24,10
2019-01-02 11:03:25,10
2019-01-02 11:03:26,10
2019-01-02 11:04:47,10
2019-01-02 11:04:48,10
2019-01-02 11:04:49,10
2019-01-02 11:04:50,10
2019-01-02 11:05:22,10
2019-01-02 11:05:23,10
2019-01-02 11:05:24,10
2019-01-02 11:05:25,10
2019-01-02 11:06:54,10
2019-01-02 11:06:55,10
2019-01-02 11:06:56,10
2019-01-02 11:06:57,10
2019-01-02 11:08:16,10
2019-01-02 11:08:17,10
2019-01-02 11:08:18,10
2019-01-02 11:08:19,10
2019-01-02 11:09:04,10
2019-01-02 11:09:05,10
2019-01-02 11:09:06,10
2019-01-02 11:09:07,10
2019-01-02 11:10:59,10
2019-01-02 11:11:00,10
2019-01-02 11:11:01,10
2019-01-02 11:11:02,10
2019-01-02 11:11:03,10
2019-01-02 11:14:02,10
2019-01-02 11:14:03,10
2019-01-02 11:14:04,10
2019-01-02 11:14:05,10
2019-01-02 11:15:01,10
2019-01-02 11:15:02,10
2019-01-02 11:15:03,10

3
run.py
View file

@ -1,7 +1,4 @@
from core.craftbeerpi import CraftBeerPi from core.craftbeerpi import CraftBeerPi
cbpi = CraftBeerPi() cbpi = CraftBeerPi()
cbpi.start() cbpi.start()

View file

@ -21,23 +21,24 @@ class ActorTestCase(AioHTTPTestCase):
resp = await self.client.post(path="/login", data={"username": "cbpi", "password": "123"}) resp = await self.client.post(path="/login", data={"username": "cbpi", "password": "123"})
assert resp.status == 200 assert resp.status == 200
resp = await self.client.request("GET", "/actor/1/on") resp = await self.client.request("POST", "/actor/1/on")
assert resp.status == 204 assert resp.status == 204
i = await self.cbpi.actor.get_one(1) i = await self.cbpi.actor.get_one(1)
print(i)
assert i.instance.state is True assert i.instance.state is True
resp = await self.client.request("GET", "/actor/1/off") resp = await self.client.request("POST", "/actor/1/off")
assert resp.status == 204 assert resp.status == 204
i = await self.cbpi.actor.get_one(1) i = await self.cbpi.actor.get_one(1)
assert i.instance.state is False assert i.instance.state is False
resp = await self.client.request("GET", "/actor/1/toggle") resp = await self.client.request("POST", "/actor/1/toggle")
assert resp.status == 204 assert resp.status == 204
i = await self.cbpi.actor.get_one(1) i = await self.cbpi.actor.get_one(1)
assert i.instance.state is True assert i.instance.state is True
resp = await self.client.request("GET", "/actor/1/toggle") resp = await self.client.request("POST", "/actor/1/toggle")
assert resp.status == 204 assert resp.status == 204
i = await self.cbpi.actor.get_one(1) i = await self.cbpi.actor.get_one(1)
assert i.instance.state is False assert i.instance.state is False
@ -73,3 +74,21 @@ class ActorTestCase(AioHTTPTestCase):
# # Delete Sensor # # Delete Sensor
resp = await self.client.delete(path="/actor/%s" % sensor_id) resp = await self.client.delete(path="/actor/%s" % sensor_id)
assert resp.status == 204 assert resp.status == 204
@unittest_run_loop
async def test_crud_negative(self):
data = {
"name": "CustomActor",
"type": "CustomActor",
"config": {
"interval": 5
}
}
# Get actor which not exists
resp = await self.client.get(path="/actor/%s" % 9999)
assert resp.status == 500
# Update not existing actor
resp = await self.client.put(path="/actor/%s" % 9999, json=data)
assert resp.status == 500

View file

@ -55,3 +55,7 @@ class ConfigTestCase(AioHTTPTestCase):
resp = await self.client.request("GET", "/config/") resp = await self.client.request("GET", "/config/")
assert resp.status == 200 assert resp.status == 200
@unittest_run_loop
async def test_get_default(self):
value = self.cbpi.config.get("HELLO_WORLD", None)
assert value == None

82
tests/test_dashboard.py Normal file
View file

@ -0,0 +1,82 @@
import aiohttp
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from core.craftbeerpi import CraftBeerPi
class DashboardTestCase(AioHTTPTestCase):
async def get_application(self):
self.cbpi = CraftBeerPi()
await self.cbpi.init_serivces()
return self.cbpi.app
@unittest_run_loop
async def test_crud(self):
data = {
"name": "MyDashboard",
}
dashboard_content = {
"type": "Test",
"x": 0,
"y": 0,
"config": {}
}
resp = await self.client.get(path="/dashboard")
assert resp.status == 200
# Add new dashboard
resp = await self.client.post(path="/dashboard/", json=data)
assert resp.status == 200
m = await resp.json()
dashboard_id = m["id"]
# Get dashboard
resp = await self.client.get(path="/dashboard/%s" % dashboard_id)
assert resp.status == 200
m2 = await resp.json()
dashboard_id = m2["id"]
# Update dashboard
resp = await self.client.put(path="/dashboard/%s" % dashboard_id, json=m)
assert resp.status == 200
# Add dashboard content
dashboard_content["dbid"] = dashboard_id
resp = await self.client.post(path="/dashboard/%s/content" % dashboard_id, json=dashboard_content)
assert resp.status == 200
m_content = await resp.json()
print("CONTENT", m_content)
content_id = m_content["id"]
# Get dashboard
resp = await self.client.get(path="/dashboard/%s/content" % (dashboard_id))
assert resp.status == 200
resp = await self.client.put(path="/dashboard/%s/content/%s/move" % (dashboard_id, content_id), json=dict(x=1,y=1))
assert resp.status == 200
resp = await self.client.delete(path="/dashboard/%s/content/%s" % (dashboard_id, content_id))
assert resp.status == 204
# Delete dashboard
resp = await self.client.delete(path="/dashboard/%s" % dashboard_id)
assert resp.status == 204
@unittest_run_loop
async def test_dashboard_controller(self):
result = await self.cbpi.dashboard.get_all()
print(result)
await self.cbpi.dashboard.add(**{"name":"Tewst"})
print(await self.cbpi.dashboard.get_one(1))
await self.cbpi.dashboard.add_content(dict(dbid=1,element_id=1,type="test",config={"name":"Manue"}))
await self.cbpi.dashboard.move_content(1,2,3)

36
tests/test_index.py Normal file
View file

@ -0,0 +1,36 @@
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from core.craftbeerpi import CraftBeerPi
class IndexTestCase(AioHTTPTestCase):
async def get_application(self):
self.cbpi = CraftBeerPi()
await self.cbpi.init_serivces()
return self.cbpi.app
@unittest_run_loop
async def test_index(self):
# Test Index Page
resp = await self.client.get(path="/")
assert resp.status == 200
@unittest_run_loop
async def test_wrong_login(self):
resp = await self.client.post(path="/login", data={"username": "beer", "password": "123"})
print("REPONSE STATUS", resp.status)
assert resp.status == 403
@unittest_run_loop
async def test_login(self):
resp = await self.client.post(path="/login", data={"username": "cbpi", "password": "123"})
print("REPONSE STATUS", resp.status)
assert resp.status == 200
resp = await self.client.get(path="/logout")
print("REPONSE STATUS LGOUT", resp.status)
assert resp.status == 200

View file

@ -18,6 +18,36 @@ class KettleTestCase(AioHTTPTestCase):
assert resp.status == 200 assert resp.status == 200
print(await resp.json()) print(await resp.json())
@unittest_run_loop
async def test_heater(self):
resp = await self.client.get("/kettle/1/heater/on")
assert resp.status == 204
resp = await self.client.get("/kettle/1/heater/off")
assert resp.status == 204
@unittest_run_loop
async def test_agitator(self):
resp = await self.client.get("/kettle/1/agitator/on")
assert resp.status == 204
resp = await self.client.get("/kettle/1/agitator/off")
assert resp.status == 204
@unittest_run_loop
async def test_temp(self):
resp = await self.client.get("/kettle/1/temp")
assert resp.status == 200
resp = await self.client.get("/kettle/1/targettemp")
assert resp.status == 200
@unittest_run_loop
async def test_automatic(self):
resp = await self.client.get("/kettle/1/automatic")
assert resp.status == 204
@unittest_run_loop @unittest_run_loop
async def test_crud(self): async def test_crud(self):
data = { data = {
@ -38,6 +68,7 @@ class KettleTestCase(AioHTTPTestCase):
assert resp.status == 200 assert resp.status == 200
m = await resp.json() m = await resp.json()
print(m)
sensor_id = m["id"] sensor_id = m["id"]
# Get sensor # Get sensor

View file

@ -0,0 +1,17 @@
import aiohttp
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from core.craftbeerpi import CraftBeerPi
class NotificationTestCase(AioHTTPTestCase):
async def get_application(self):
self.cbpi = CraftBeerPi()
await self.cbpi.init_serivces()
return self.cbpi.app
@unittest_run_loop
async def test_actor_switch(self):
self.cbpi.notify("test", "test")

View file

@ -21,7 +21,6 @@ class SensorTestCase(AioHTTPTestCase):
} }
} }
# Add new sensor # Add new sensor
resp = await self.client.post(path="/sensor/", json=data) resp = await self.client.post(path="/sensor/", json=data)
assert resp.status == 200 assert resp.status == 200
@ -43,5 +42,3 @@ class SensorTestCase(AioHTTPTestCase):
# # Delete Sensor # # Delete Sensor
resp = await self.client.delete(path="/sensor/%s" % sensor_id) resp = await self.client.delete(path="/sensor/%s" % sensor_id)
assert resp.status == 204 assert resp.status == 204
await asyncio.sleep(5)

70
tests/test_step.py Normal file
View file

@ -0,0 +1,70 @@
import asyncio
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from core.craftbeerpi import CraftBeerPi
class StepTestCase(AioHTTPTestCase):
async def get_application(self):
self.cbpi = CraftBeerPi()
await self.cbpi.init_serivces()
return self.cbpi.app
@unittest_run_loop
async def test_get(self):
resp = await self.client.request("GET", "/step")
assert resp.status == 200
resp = await self.client.request("GET", "/step/types")
assert resp.status == 200
@unittest_run_loop
async def test_crud(self):
data = {
"name": "Test",
"type": "CustomStepCBPi",
}
# Add new sensor
resp = await self.client.post(path="/step/", json=data)
assert resp.status == 200
m = await resp.json()
print(m)
sensor_id = m["id"]
# Get sensor
resp = await self.client.get(path="/step/%s" % sensor_id)
assert resp.status == 200
m2 = await resp.json()
sensor_id = m2["id"]
# Update Sensor
resp = await self.client.put(path="/step/%s" % sensor_id, json=m)
assert resp.status == 200
# # Delete Sensor
resp = await self.client.delete(path="/step/%s" % sensor_id)
assert resp.status == 204
@unittest_run_loop
async def test_process(self):
resp = await self.client.request("GET", "/step/stop")
assert resp.status == 204
resp = await self.client.request("GET", "/step/start")
assert resp.status == 204
resp = await self.client.request("GET", "/step/next")
assert resp.status == 204
resp = await self.client.request("GET", "/step/stop")
assert resp.status == 204

29
tests/test_system.py Normal file
View file

@ -0,0 +1,29 @@
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from core.craftbeerpi import CraftBeerPi
class IndexTestCase(AioHTTPTestCase):
async def get_application(self):
self.cbpi = CraftBeerPi()
await self.cbpi.init_serivces()
return self.cbpi.app
@unittest_run_loop
async def test_endpoints(self):
# Test Index Page
resp = await self.client.post(path="/system/restart")
assert resp.status == 200
resp = await self.client.post(path="/system/shutdown")
assert resp.status == 200
resp = await self.client.get(path="/system/jobs")
assert resp.status == 200
resp = await self.client.get(path="/system/events")
assert resp.status == 200

15
tests/test_utils.py Normal file
View file

@ -0,0 +1,15 @@
from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop
from core.craftbeerpi import CraftBeerPi, load_config
class UtilsTestCase(AioHTTPTestCase):
async def get_application(self):
self.cbpi = CraftBeerPi()
await self.cbpi.init_serivces()
return self.cbpi.app
@unittest_run_loop
async def test_load_file(self):
assert load_config("") is None