|
|
@@ -27,16 +27,19 @@ import aiohttp |
|
|
|
import asyncio |
|
|
|
import concurrent |
|
|
|
import logging |
|
|
|
import json |
|
|
|
import mock |
|
|
|
import os |
|
|
|
import shutil |
|
|
|
import solardash |
|
|
|
import tempfile |
|
|
|
import unittest |
|
|
|
import urllib |
|
|
|
|
|
|
|
logging.basicConfig(level=logging.DEBUG) |
|
|
|
#logging.basicConfig(level=logging.DEBUG) |
|
|
|
|
|
|
|
from aiohttp import web |
|
|
|
from RainEagle.parse import LogDir as RELogDir, _cmaiter |
|
|
|
from RainEagle.parse import LogDir as RELogDir, _cmaiter, MeterRead |
|
|
|
|
|
|
|
# https://twitter.com/encthenet/status/1220412987732787200?s=20 |
|
|
|
aiter = lambda x: x.__aiter__() |
|
|
@@ -106,10 +109,21 @@ class SolarDataWS(object): |
|
|
|
|
|
|
|
injecttask = asyncio.create_task(injector()) |
|
|
|
|
|
|
|
#pending = [] |
|
|
|
async for msg in ws: |
|
|
|
if msg.type == aiohttp.WSMsgType.TEXT and msg.data == 'q': |
|
|
|
break |
|
|
|
else: |
|
|
|
break |
|
|
|
elif msg.type == aiohttp.WSMsgType.TEXT: |
|
|
|
fun, data = msg.data.split(' ', 1) |
|
|
|
try: |
|
|
|
fun = getattr(self, 'wst_%s' % fun) |
|
|
|
# XXX add tests to make this a task |
|
|
|
#pending.append(asyncio.create_task(fun(ws, data))) |
|
|
|
await fun(ws, data) |
|
|
|
except Exception: # pragma: no cover |
|
|
|
import traceback; traceback.print_exc() |
|
|
|
print('failed to handle msg:', repr(msg)) |
|
|
|
else: # pragma: no cover |
|
|
|
print('unknown msg:', repr(msg)) |
|
|
|
|
|
|
|
injecttask.cancel() |
|
|
@@ -118,6 +132,14 @@ class SolarDataWS(object): |
|
|
|
|
|
|
|
return ws |
|
|
|
|
|
|
|
async def wst_win(self, ws, data): |
|
|
|
start, stop = (int(x) / 1000 for x in data.split()) |
|
|
|
|
|
|
|
griddata = [ (x.meterts, x.load * 1000) for x in self._raineagle[start:stop] ] |
|
|
|
|
|
|
|
obj = dict(production=[], grid=griddata, consumption=[]) |
|
|
|
await ws.send_str('windata %s' % json.dumps(obj)) |
|
|
|
|
|
|
|
def get_routes(self): |
|
|
|
return [ |
|
|
|
web.get('/solar.ws', self.websocket_handler), |
|
|
@@ -341,3 +363,49 @@ class Test(unittest.TestCase): |
|
|
|
self.assertEqual(r[1].data, 'ng 1.0000') |
|
|
|
finally: |
|
|
|
await runner.cleanup() |
|
|
|
|
|
|
|
@async_test |
|
|
|
@mock.patch('solardash.RELogDir.__getitem__') |
|
|
|
async def test_winowdata(self, relogdir): |
|
|
|
loop = asyncio.get_event_loop() |
|
|
|
|
|
|
|
runner = web.AppRunner(self._app) |
|
|
|
await runner.setup() |
|
|
|
try: |
|
|
|
site = web.TCPSite(runner, 'localhost', self._webport) |
|
|
|
await site.start() |
|
|
|
|
|
|
|
# Test the websocket |
|
|
|
r = [] |
|
|
|
|
|
|
|
async with aiohttp.ClientSession() as session, \ |
|
|
|
session.ws_connect(self.makeurl('solar.ws')) as ws: |
|
|
|
startts = 128743 |
|
|
|
endts = 1987343 |
|
|
|
|
|
|
|
meterdata = [ MeterRead(x * 2, x * 2 + 1, 'bogus', |
|
|
|
x, 12, 'kW', x * 5, -x * 5, |
|
|
|
'kW') for x in (1, 2, 3, 4) ] |
|
|
|
data = [ [x.meterts, x.load * 1000] for x in meterdata ] |
|
|
|
relogdir.return_value = meterdata |
|
|
|
windataresp = 'this is some response' |
|
|
|
|
|
|
|
# send the window command |
|
|
|
await ws.send_str('win %s %s' % (startts, |
|
|
|
endts)) |
|
|
|
|
|
|
|
async for msg in ws: |
|
|
|
r.append(msg) |
|
|
|
if len(r) == 1: |
|
|
|
break |
|
|
|
|
|
|
|
# we get passed in miliseconds from JS, but |
|
|
|
# we want seconds |
|
|
|
relogdir.assert_called_with(slice(startts / |
|
|
|
1000, endts / 1000)) |
|
|
|
self.assertEqual(r[0].type, aiohttp.WSMsgType.TEXT) |
|
|
|
obj = json.loads(r[0].data.split(' ', 1)[1]) |
|
|
|
self.assertEqual(obj, dict(production=[], |
|
|
|
grid=data, consumption=[])) |
|
|
|
finally: |
|
|
|
await runner.cleanup() |