|
|
|
@ -6,11 +6,12 @@ import './App.css'; |
|
|
|
|
|
|
|
|
|
function App() { |
|
|
|
|
const [data, setData] = useState(false); |
|
|
|
|
const [history, setHistory] = useState(false); |
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
const get = async() => { |
|
|
|
|
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); |
|
|
|
|
} catch (error) { |
|
|
|
|
setData(false); |
|
|
|
@ -18,97 +19,94 @@ function App() { |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
get(); |
|
|
|
|
const interval = setInterval(get, 1000); |
|
|
|
|
const interval = setInterval(get, 30000); |
|
|
|
|
return () => clearInterval(interval); |
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
const listen = () => { |
|
|
|
|
var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); |
|
|
|
|
var myArrayBuffer = audioCtx.createBuffer(2, audioCtx.sampleRate * 5, audioCtx.sampleRate); |
|
|
|
|
for (var channel = 0; channel < myArrayBuffer.numberOfChannels; channel++) { |
|
|
|
|
var nowBuffering = myArrayBuffer.getChannelData(channel); |
|
|
|
|
for (var i = 0; i < myArrayBuffer.length; i++) { |
|
|
|
|
nowBuffering[i] = data.history[i % data.history.length].total / 24000.0; |
|
|
|
|
useEffect(() => { |
|
|
|
|
const get = async() => { |
|
|
|
|
try { |
|
|
|
|
const date = moment().format('YYYY-MM-DD'); |
|
|
|
|
const res = await axios.get('https://solar-api.dns.t0.vc/history/'+date); |
|
|
|
|
setHistory(res.data); |
|
|
|
|
} catch (error) { |
|
|
|
|
setHistory(false); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
var source = audioCtx.createBufferSource(); |
|
|
|
|
source.buffer = myArrayBuffer; |
|
|
|
|
source.connect(audioCtx.destination); |
|
|
|
|
source.start(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
get(); |
|
|
|
|
const interval = setInterval(get, 30000); |
|
|
|
|
return () => clearInterval(interval); |
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<div> |
|
|
|
|
{data ? |
|
|
|
|
<div> |
|
|
|
|
<ResponsiveContainer width='100%' height={300}> |
|
|
|
|
<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')} |
|
|
|
|
/> |
|
|
|
|
{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='total' |
|
|
|
|
name='Watts' |
|
|
|
|
stroke='#ff5900' |
|
|
|
|
strokeWidth={2} |
|
|
|
|
dot={false} |
|
|
|
|
animationDuration={1000} |
|
|
|
|
/> |
|
|
|
|
</LineChart> |
|
|
|
|
</ResponsiveContainer> |
|
|
|
|
<Line |
|
|
|
|
type='monotone' |
|
|
|
|
dataKey='actual_total' |
|
|
|
|
name='Watts' |
|
|
|
|
stroke='#ff5900' |
|
|
|
|
strokeWidth={2} |
|
|
|
|
dot={false} |
|
|
|
|
animationDuration={1000} |
|
|
|
|
/> |
|
|
|
|
</LineChart> |
|
|
|
|
</ResponsiveContainer> |
|
|
|
|
: |
|
|
|
|
<p>Loading...</p> |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
<button onClick={listen}>Listen</button> |
|
|
|
|
{data ? |
|
|
|
|
<div className='container'> |
|
|
|
|
<p>Total: {data.actual_total} W — {parseInt(data.actual_total / 5985 * 100)}%</p> |
|
|
|
|
|
|
|
|
|
{data.night ? |
|
|
|
|
<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> |
|
|
|
|
|
|
|
|
|
<p>Today: {data.today_energy} kWh</p> |
|
|
|
|
<p>Updated: {data.timestamp.split(' ')[1]}</p> |
|
|
|
|
|
|
|
|
|
<p>Updated: {data.timestamp.split(' ')[1]}</p> |
|
|
|
|
<p>Individual panels:</p> |
|
|
|
|
|
|
|
|
|
<p>Individual panels:</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> |
|
|
|
|
|
|
|
|
|
<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> |
|
|
|
|
{i != 2 && |
|
|
|
|
<div |
|
|
|
|
className='panel' |
|
|
|
|
style={{ backgroundColor: `hsl(21, 100%, ${x.power[1]/315*50}%)` }} |
|
|
|
|
> |
|
|
|
|
<div className='panel-label'> |
|
|
|
|
{x.power[1]} |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
{i != 2 && |
|
|
|
|
<div |
|
|
|
|
className='panel' |
|
|
|
|
style={{ backgroundColor: `hsl(21, 100%, ${x.power[1]/315*50}%)` }} |
|
|
|
|
> |
|
|
|
|
<div className='panel-label'> |
|
|
|
|
{x.power[1]} |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
} |
|
|
|
|
</> |
|
|
|
|
)} |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
} |
|
|
|
|
</div> |
|
|
|
|
} |
|
|
|
|
</> |
|
|
|
|
)} |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
: |
|
|
|
|
<p>Loading...</p> |
|
|
|
|