Compare commits
3 Commits
f2e9b389b2
...
master
Author | SHA1 | Date | |
---|---|---|---|
278d30c421 | |||
f01eeacbce | |||
af87378fd3 |
@@ -47,3 +47,8 @@ p {
|
|||||||
margin: 0.25em;
|
margin: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.recharts-wrapper p {
|
||||||
|
color: initial;
|
||||||
|
font-size: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -6,11 +6,12 @@ import './App.css';
|
|||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [data, setData] = useState(false);
|
const [data, setData] = useState(false);
|
||||||
|
const [history, setHistory] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const get = async() => {
|
const get = async() => {
|
||||||
try {
|
try {
|
||||||
const res = await axios.get('https://reg.t0.vc/solar.json');
|
const res = await axios.get('https://solar-api.dns.t0.vc/data');
|
||||||
setData(res.data);
|
setData(res.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setData(false);
|
setData(false);
|
||||||
@@ -18,97 +19,94 @@ function App() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
get();
|
get();
|
||||||
const interval = setInterval(get, 1000);
|
const interval = setInterval(get, 30000);
|
||||||
return () => clearInterval(interval);
|
return () => clearInterval(interval);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const listen = () => {
|
useEffect(() => {
|
||||||
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
const get = async() => {
|
||||||
var myArrayBuffer = audioCtx.createBuffer(2, audioCtx.sampleRate * 5, audioCtx.sampleRate);
|
try {
|
||||||
for (var channel = 0; channel < myArrayBuffer.numberOfChannels; channel++) {
|
const date = moment().format('YYYY-MM-DD');
|
||||||
var nowBuffering = myArrayBuffer.getChannelData(channel);
|
const res = await axios.get('https://solar-api.dns.t0.vc/history/'+date);
|
||||||
for (var i = 0; i < myArrayBuffer.length; i++) {
|
setHistory(res.data);
|
||||||
nowBuffering[i] = data.history[i % data.history.length].total / 24000.0;
|
} catch (error) {
|
||||||
|
setHistory(false);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
var source = audioCtx.createBufferSource();
|
|
||||||
source.buffer = myArrayBuffer;
|
get();
|
||||||
source.connect(audioCtx.destination);
|
const interval = setInterval(get, 30000);
|
||||||
source.start();
|
return () => clearInterval(interval);
|
||||||
}
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
{history ?
|
||||||
|
<ResponsiveContainer width='100%' height={300}>
|
||||||
|
<LineChart data={history}>
|
||||||
|
<XAxis
|
||||||
|
dataKey='time'
|
||||||
|
minTickGap={10}
|
||||||
|
tickFormatter={timeStr => moment(timeStr).format('HH:mm')}
|
||||||
|
/>
|
||||||
|
<YAxis
|
||||||
|
domain={[0, 6000]}
|
||||||
|
/>
|
||||||
|
<CartesianGrid strokeDasharray='3 3'/>
|
||||||
|
<Tooltip
|
||||||
|
labelFormatter={timeStr => 'Time: ' + moment(timeStr).format('HH:mm')}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Line
|
||||||
|
type='monotone'
|
||||||
|
dataKey='actual_total'
|
||||||
|
name='Watts'
|
||||||
|
stroke='#ff5900'
|
||||||
|
strokeWidth={2}
|
||||||
|
dot={false}
|
||||||
|
animationDuration={1000}
|
||||||
|
/>
|
||||||
|
</LineChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
:
|
||||||
|
<p>Loading...</p>
|
||||||
|
}
|
||||||
|
|
||||||
{data ?
|
{data ?
|
||||||
<div>
|
<div className='container'>
|
||||||
<ResponsiveContainer width='100%' height={300}>
|
<p>Total: {data.actual_total} W — {parseInt(data.actual_total / 5985 * 100)}%</p>
|
||||||
<LineChart data={data.history}>
|
|
||||||
<XAxis
|
|
||||||
dataKey='time'
|
|
||||||
minTickGap={10}
|
|
||||||
tickFormatter={timeStr => moment.utc(timeStr).format('HH:mm')}
|
|
||||||
/>
|
|
||||||
<YAxis />
|
|
||||||
<CartesianGrid strokeDasharray='3 3'/>
|
|
||||||
<Tooltip
|
|
||||||
labelFormatter={timeStr => 'Time: ' + moment.utc(timeStr).format('HH:mm')}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Line
|
<p>Today: {data.today_energy} kWh</p>
|
||||||
type='monotone'
|
|
||||||
dataKey='total'
|
|
||||||
name='Watts'
|
|
||||||
stroke='#ff5900'
|
|
||||||
strokeWidth={2}
|
|
||||||
dot={false}
|
|
||||||
animationDuration={1000}
|
|
||||||
/>
|
|
||||||
</LineChart>
|
|
||||||
</ResponsiveContainer>
|
|
||||||
|
|
||||||
<button onClick={listen}>Listen</button>
|
<p>Updated: {data.timestamp.split(' ')[1]}</p>
|
||||||
|
|
||||||
{data.night ?
|
<p>Individual panels:</p>
|
||||||
<div className='container'>
|
|
||||||
<p>The sun has set 😴</p>
|
|
||||||
</div>
|
|
||||||
:
|
|
||||||
<div className='container'>
|
|
||||||
<p>Total: {data.actual_total} W — {parseInt(data.actual_total / 5985 * 100)}%</p>
|
|
||||||
|
|
||||||
<p>Today: {data.today_energy} kWh</p>
|
<div className='panels'>
|
||||||
|
{Object.values(data.inverters).map((x, i) =>
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className='panel'
|
||||||
|
style={{ backgroundColor: `hsl(21, 100%, ${x.power[0]/315*50}%)` }}
|
||||||
|
>
|
||||||
|
<div className='panel-label'>
|
||||||
|
{x.power[0]}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p>Updated: {data.timestamp.split(' ')[1]}</p>
|
{i != 2 &&
|
||||||
|
<div
|
||||||
<p>Individual panels:</p>
|
className='panel'
|
||||||
|
style={{ backgroundColor: `hsl(21, 100%, ${x.power[1]/315*50}%)` }}
|
||||||
<div className='panels'>
|
>
|
||||||
{Object.values(data.inverters).map((x, i) =>
|
<div className='panel-label'>
|
||||||
<>
|
{x.power[1]}
|
||||||
<div
|
|
||||||
className='panel'
|
|
||||||
style={{ backgroundColor: `hsl(21, 100%, ${x.power[0]/315*50}%)` }}
|
|
||||||
>
|
|
||||||
<div className='panel-label'>
|
|
||||||
{x.power[0]}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{i != 2 &&
|
}
|
||||||
<div
|
</>
|
||||||
className='panel'
|
)}
|
||||||
style={{ backgroundColor: `hsl(21, 100%, ${x.power[1]/315*50}%)` }}
|
</div>
|
||||||
>
|
|
||||||
<div className='panel-label'>
|
|
||||||
{x.power[1]}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<p>Loading...</p>
|
<p>Loading...</p>
|
||||||
|
@@ -7,13 +7,13 @@ logging.getLogger('aiohttp').setLevel(logging.DEBUG if os.environ.get('DEBUG') e
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
from APSystemsECUR import APSystemsECUR
|
from APSystemsECUR import APSystemsECUR
|
||||||
|
|
||||||
ECU_IP = '192.168.69.153'
|
ECU_IP = '192.168.69.153'
|
||||||
LISTEN_IP = '192.168.69.100'
|
LISTEN_IP = '192.168.69.106'
|
||||||
ecu = APSystemsECUR(ECU_IP)
|
ecu = APSystemsECUR(ECU_IP)
|
||||||
app = web.Application()
|
app = web.Application()
|
||||||
prev_ecu_timestamp = None
|
prev_ecu_timestamp = None
|
||||||
@@ -60,7 +60,7 @@ async def get_data():
|
|||||||
|
|
||||||
if data['timestamp'] != prev_ecu_timestamp:
|
if data['timestamp'] != prev_ecu_timestamp:
|
||||||
total = 0
|
total = 0
|
||||||
timestamp = datetime.utcnow()
|
utctime = datetime.now(timezone.utc)
|
||||||
|
|
||||||
for i in data['inverters'].values():
|
for i in data['inverters'].values():
|
||||||
total += i['power'][0]
|
total += i['power'][0]
|
||||||
@@ -73,7 +73,7 @@ async def get_data():
|
|||||||
points = []
|
points = []
|
||||||
for i in data['inverters'].values():
|
for i in data['inverters'].values():
|
||||||
points.append({
|
points.append({
|
||||||
'time': timestamp,
|
'time': utctime,
|
||||||
'measurement': 'inverter',
|
'measurement': 'inverter',
|
||||||
'tags': {'ecu': data['ecu_id'], 'inverter': i['uid']},
|
'tags': {'ecu': data['ecu_id'], 'inverter': i['uid']},
|
||||||
'fields': {
|
'fields': {
|
||||||
@@ -85,7 +85,7 @@ async def get_data():
|
|||||||
})
|
})
|
||||||
|
|
||||||
points.append({
|
points.append({
|
||||||
'time': timestamp,
|
'time': utctime,
|
||||||
'measurement': 'panel',
|
'measurement': 'panel',
|
||||||
'tags': {'ecu': data['ecu_id'], 'inverter': i['uid'], 'channel': '0'},
|
'tags': {'ecu': data['ecu_id'], 'inverter': i['uid'], 'channel': '0'},
|
||||||
'fields': {
|
'fields': {
|
||||||
@@ -96,7 +96,7 @@ async def get_data():
|
|||||||
})
|
})
|
||||||
|
|
||||||
points.append({
|
points.append({
|
||||||
'time': timestamp,
|
'time': utctime,
|
||||||
'measurement': 'panel',
|
'measurement': 'panel',
|
||||||
'tags': {'ecu': data['ecu_id'], 'inverter': i['uid'], 'channel': '1'},
|
'tags': {'ecu': data['ecu_id'], 'inverter': i['uid'], 'channel': '1'},
|
||||||
'fields': {
|
'fields': {
|
||||||
@@ -107,7 +107,7 @@ async def get_data():
|
|||||||
})
|
})
|
||||||
|
|
||||||
points.append({
|
points.append({
|
||||||
'time': timestamp,
|
'time': utctime,
|
||||||
'measurement': 'ecu',
|
'measurement': 'ecu',
|
||||||
'tags': {'ecu': data['ecu_id']},
|
'tags': {'ecu': data['ecu_id']},
|
||||||
'fields': {
|
'fields': {
|
||||||
@@ -165,6 +165,6 @@ if __name__ == '__main__':
|
|||||||
app.router.add_get('/history/{date}', history)
|
app.router.add_get('/history/{date}', history)
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
loop.create_task(run_proxies())
|
a = loop.create_task(run_proxies())
|
||||||
loop.create_task(get_data())
|
b = loop.create_task(get_data())
|
||||||
web.run_app(app, port=6901)
|
web.run_app(app, port=6901)
|
||||||
|
Reference in New Issue
Block a user