Last active
May 6, 2023 13:04
-
-
Save kenwebb/ea03a54c5c871ecd1563574f8b718b6e to your computer and use it in GitHub Desktop.
Pumped Hydro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<!--Xholon Workbook http://www.primordion.com/Xholon/gwt/ MIT License, Copyright (C) Ken Webb, Sat May 06 2023 09:03:54 GMT-0400 (Eastern Daylight Saving Time)--> | |
<XholonWorkbook> | |
<Notes><![CDATA[ | |
Xholon | |
------ | |
Title: Pumped Hydro | |
Description: | |
Url: http://www.primordion.com/Xholon/gwt/ | |
InternalName: ea03a54c5c871ecd1563574f8b718b6e | |
Keywords: | |
My Notes | |
-------- | |
4 May 2023 | |
In this workbook, I want to: | |
- build a simple Xholon model based on the ideas and ojects in the NYTimes article | |
- use hardware sensors to measure real light levels in the house or outside | |
- use the generated data to decide what to do in the model | |
- use simulated solar energy when light is available | |
- use simulated pumped hydro when light levels are low or non-existent | |
I will use mqtt, node-red, grove sensors, picow/arduino/pizero | |
- see my folders from late 2022 and early 2023, and my mqtt01 gist (14 Jan 2023) | |
Write down all the steps that I used at that time. | |
I was able to get the sensor data all the way to a running Xholon app. | |
Steps | |
===== | |
node-red (not required) | |
-------- | |
cd | |
node-red | |
4 May 08:51:30 - [info] | |
Welcome to Node-RED | |
.... | |
Server now running at http://127.0.0.1:1880/ | |
.... | |
opened /tmp/sqlite ok | |
Connected to broker: mqtt://localhost:1883 | |
- Flow 5 is active | |
- it is connected to mosquitto broker and sqlite which are both automatically available | |
Grove Beginner Kit | |
------------------ | |
Arduino code: | |
~/Arduino/seeed/sketch_jan18d_KenzEnviro03/sketch_jan18d_KenzEnviro03.ino | |
- with Arduino on Grove kit plugged into my HP ZBook USB port | |
minicom -b 115200 -o -D /dev/ttyUSB0 | |
- this works | |
OR (this works): | |
stty -F /dev/ttyUSB0 115200 raw -clocal -echo | |
mosquitto_pub -h 192.168.1.15 -t KenzEnviro/thl -l < /dev/ttyUSB0 | |
Xholon workook mqtt01 | |
--------------------- | |
http://127.0.0.1:8081/Xholon.html?app=mqtt01&src=lstr&gui=clsc&jslib=mqttws31 | |
http://127.0.0.1:8081/war/Xholon.html?app=mqtt01&src=lstr&gui=clsc&jslib=mqttws31.min | |
- this sort-of works (but with an error that causes no data acquired) | |
- ut see 5 May below :) | |
5 May 2023 - this works | |
----------------------- | |
- I haven't changed any code, but the following sequence of events now works | |
(1) plug the Grove Beginner Kit into the HP ZBook USB | |
(2) in terminal A (base) ken@ken-HP-ZBook-15-G2:~$ | |
stty -F /dev/ttyUSB0 115200 raw -clocal -echo | |
mosquitto_pub -h 192.168.1.15 -t KenzEnviro/thl -l < /dev/ttyUSB0 | |
(3) in terminal B (base) ken@ken-HP-ZBook-15-G2:~$ | |
mosquitto_sub -d -t KenzEnviro/thl | |
- this visually confirms that I can get correct data | |
Client null sending CONNECT | |
Client null received CONNACK (0) | |
Client null sending SUBSCRIBE (Mid: 1, Topic: KenzEnviro/thl, QoS: 0, Options: 0x00) | |
Client null received SUBACK | |
Subscribed (mid: 1): 0 | |
Client null received PUBLISH (d0, q0, r0, m0, 'KenzEnviro/thl', ... (89 bytes)) | |
{"t":23.4,"h":31.5,"l":10,"s":109,"m":0,"w":"OfK","p":"aunogr","r":[2023,5,5,5,9,56,54]} | |
Client null sending PINGREQ | |
Client null received PINGRESP | |
Client null received PUBLISH (d0, q0, r0, m0, 'KenzEnviro/thl', ... (88 bytes)) | |
{"t":23.4,"h":31.5,"l":9,"s":121,"m":0,"w":"OfK","p":"aunogr","r":[2023,5,5,5,9,57,54]} | |
(4) http://127.0.0.1:8081/Xholon.html?app=mqtt01&src=lstr&gui=clsc&jslib=mqttws31 | |
Connecting to: 192.168.1.15 on port: 8080 | |
Subscribing to topic: KenzEnviro/thl | |
Temperature,Humidity,Light,Sound,Motion,Where,Datetime | |
23.4,31.4,8,70,0,OfK,05/05/2023T09:58:54 | |
23.4,31.4,7,92,0,OfK,05/05/2023T09:59:54 | |
23.4,31.5,7,51,0,OfK,05/05/2023T10:00:54 | |
23.4,31.6,7,69,0,OfK,05/05/2023T10:01:54 | |
23.5,31.6,6,64,0,OfK,05/05/2023T10:02:54 | |
23.5,31.5,7,91,0,OfK,05/05/2023T10:03:54 | |
23.5,31.5,7,123,0,OfK,05/05/2023T10:04:54 | |
23.5,31.6,9,30,0,OfK,05/05/2023T10:05:54 | |
23.5,31.6,7,71,0,OfK,05/05/2023T10:06:54 | |
23.5,31.6,7,128,0,OfK,05/05/2023T10:07:54 | |
23.5,31.6,7,108,0,OfK,05/05/2023T10:08:54 | |
23.5,31.5,9,113,0,OfK,05/05/2023T10:09:54 | |
How to run the Pumped Hydro workbook app | |
---------------------------------------- | |
http://127.0.0.1:8081/Xholon.html?app=Pumped+Hydro&src=lstr&gui=clsc&jslib=mqttws31 | |
Connecting to: 192.168.1.15 on port: 8080 | |
water_50 0 | |
water_54 1000000 | |
Subscribing to topic: KenzEnviro/thl | |
Temperature,Humidity,Light,Sound,Motion,Where,Datetime | |
24.6,32.3,27,127,0,OfK,05/05/2023T13:38:55 | |
27 999973 27 | |
24.5,32.1,26,156,0,OfK,05/05/2023T13:39:55 | |
26 999947 53 | |
24.5,32,25,165,0,OfK,05/05/2023T13:40:55 | |
25 999922 78 | |
24.5,31.8,26,150,0,OfK,05/05/2023T13:41:55 | |
26 999896 104 | |
24.4,31.8,24,64,0,OfK,05/05/2023T13:42:55 | |
24 999872 128 | |
SVG visualization | |
----------------- | |
- see Coin Flipping Example http://127.0.0.1:8081/wb/editwb.html?app=2159078&src=gist | |
References | |
---------- | |
() https://www.nytimes.com/interactive/2023/05/02/climate/hydroelectric-power-energy.html | |
NYTimes article, 2 May | |
Is It a Lake, or a Battery? A New Kind of Hydropower Is Spreading Fast. | |
By Mira Rojanasakul and Max BearakMay 2, 2023 | |
These systems involve two reservoirs: one on top of a hill and another at the bottom. | |
When electricity generated from nearby power plants exceeds demand, | |
it’s used to pump water uphill, essentially filling the upper reservoir as a battery. | |
Later, when electricity demand spikes, | |
water is released to the lower reservoir through a turbine, generating power. | |
() my notebook 2 May 2023 | |
]]></Notes> | |
<_-.XholonClass> | |
<PhysicalSystem/> | |
<ThlClient/> | |
<Reservoir/> | |
<Hill/> | |
<TopOfHill/> | |
<BottomOfHill/> | |
<Turbine/> | |
<Water/> | |
<ElectricitySource> | |
<SolarPanel/> | |
<WindTurbine/> | |
<FossilFuelPlant/> | |
</ElectricitySource> | |
</_-.XholonClass> | |
<xholonClassDetails> | |
</xholonClassDetails> | |
<PhysicalSystem> | |
<ThlClient host="192.168.1.15" port="8080" clientidPrefix="clientID-" topic="KenzEnviro/thl" solarPanel=""/> | |
<Hill> | |
<TopOfHill> | |
<Reservoir roleName="top"> | |
<Water count="0"/> | |
</Reservoir> | |
</TopOfHill> | |
<Turbine/> <!-- converts falling water into electricity --> | |
<BottomOfHill> | |
<Reservoir roleName="bottom"> | |
<Water count="5000"/> | |
</Reservoir> | |
</BottomOfHill> | |
</Hill> | |
<SolarPanel/> <!-- converts light into electricity, and pumps water uphill --> | |
</PhysicalSystem> | |
<ThlClientbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
var me, beh = { | |
postConfigure: function() { | |
me = this.cnode.parent(); | |
$wnd.xh.param("TimeStepInterval", 500); | |
this.startConnect(); | |
}, | |
startConnect: function() { | |
me.clientID = me.clientidPrefix + parseInt(Math.random() * 100); | |
me.println("Connecting to: " + me.host + " on port: " + me.port); | |
me.client = new $wnd.Paho.MQTT.Client(me.host, Number(me.port), me.clientID); | |
me.client.onConnectionLost = this.onConnectionLost; | |
me.client.onMessageArrived = this.onMessageArrived; | |
me.client.connect({ | |
onSuccess: this.onConnect, | |
//userName:"USERNAME", | |
//password:"PASSWORD" | |
}); | |
}, | |
onConnect: function() { | |
me.println("Subscribing to topic: " + me.topic); | |
me.client.subscribe(me.topic); | |
me.println("Temperature,Humidity,Light,Sound,Motion,Where,Datetime"); | |
}, | |
onConnectionLost: function(responseObject) { | |
me.println("Connection Lost"); | |
if (responseObject.errorCode !== 0) { | |
me.println("onConnectionLost: " + responseObject.errorMessage); | |
} | |
}, | |
onMessageArrived: function(message) { | |
//me.println("Topic: " + message.destinationName + " " + message.payloadString); | |
beh.processPayload(message.payloadString); | |
}, | |
startDisconnect: function() { | |
me.client.disconnect(); | |
me.println("Disconnected"); | |
}, | |
processPayload: function(json) { | |
// json is a JSON Oject ex: {"t":24.2,"h":33.0,"l":1248} {"t":24.3,"h":37.0,"l":40265,"m":0,"r":[2023, 1, 9, 1, 11, 49, 3]} | |
var jsobj = JSON.parse(json); | |
var dt = jsobj.r.map(ele => ele < 10 ? "0" + ele : "" + ele); | |
me.println(`${jsobj.t},${jsobj.h},${jsobj.l},${jsobj.s},${jsobj.m},${jsobj.w},${dt[1]}/${dt[2]}/${dt[0]}T${dt[4]}:${dt[5]}:${dt[6]}`); | |
me.solarPanel.msg(101, jsobj.l.toString()); | |
} | |
} | |
//# sourceURL=ThlClientbehavior.js | |
]]></ThlClientbehavior> | |
<SolarPanelbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[ | |
var me, top, bottom, rectSVG, beh = { | |
postConfigure: function() { | |
me = this.cnode.parent(); | |
const lightSource = me.parent().first(); // ThlClient | |
lightSource.solarPanel = this.cnode; | |
top = me.parent().first().next().first().first().first(); | |
bottom = me.parent().first().next().first().next().next().first().first(); | |
top.count = Number(top.count); | |
bottom.count = Number(bottom.count); | |
me.println(top.name() + " " + top.count); | |
me.println(bottom.name() + " " + bottom.count); | |
}, | |
processReceivedMessage: function(msg) { | |
var amount = Number(msg.data); | |
// move msg.data amount of water from bottom to top reservoir | |
bottom.count -= amount; | |
top.count += amount; | |
me.println("" + amount + " " + bottom.count + " " + top.count); | |
// SVG | |
if (!rectSVG) { | |
var svg = $doc.getElementById("xhsvg").firstElementChild.firstElementChild; | |
rectSVG = svg.getElementById("PhysicalSystem/Hill/TopOfHill"); | |
} | |
rectSVG.setAttributeNS(null, 'height', top.count * 0.1); | |
$wnd.console.log('height', top.count, top.count * 0.1, rectSVG); | |
} | |
} | |
//# sourceURL=SolarPanelbehavior.js | |
]]></SolarPanelbehavior> | |
<SvgClient><Attribute_String roleName="svgUri"><![CDATA[data:image/svg+xml, | |
<svg width="100" height="500" xmlns="http://www.w3.org/2000/svg"> | |
<g> | |
<title>PhysicalSystem</title> | |
<rect id="PhysicalSystem/Hill/BottomOfHill" fill="#1E90FF" height="500" width="50" x="25" y="0"/> | |
<rect id="PhysicalSystem/Hill/TopOfHill" fill="#00BFFF" height="1" width="50" x="25" y="0"/> | |
</g> | |
</svg> | |
]]></Attribute_String><Attribute_String roleName="setup">${MODELNAME_DEFAULT},${SVGURI_DEFAULT}</Attribute_String></SvgClient> | |
</XholonWorkbook> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment