<div dir="ltr"><div>Oooh.. I can now see this might actually happen.</div><div><br></div><div>Btw, one of the nice things about the async subscriptions is that the form (like the dashboard) doesn't freeze when loading up.. so the page loads and renders and then the metrics kinda of just slide on in. I don't believe it takes as long as loading all metrics - but also it feels from a UI perspective even shorter because the UI loads quicker.</div><div><br></div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, 14 Dec 2022 at 05:42, Michael Balzer <<a href="mailto:dexter@expeedo.de">dexter@expeedo.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div>
Michael,<br>
<br>
<div>Am 13.12.22 um 00:00 schrieb Michael
Geddes:<br>
</div>
<blockquote type="cite">
<div dir="ltr">I'll go back and revise the topic subscriptions
stuff wrt metrics etc. with the stuff I have done.
<div><br>
</div>
<div>I have implemented metric subscriptions and also
implemented async getters in the dashboard just to see what
the burden is, and tbh it's not too bad! I had no real
expectation that this would end up in the final code and it
was more just to further my understanding. What I've done
does require a 'get and subscribe' function added to the
websocket.</div>
<div><br>
</div>
<div><b>unit getsub <i>CallID</i> m<i>etricName</i></b></div>
<div>Which subscribes to the metric, but also returns a result
something like</div>
<div>{ result : { ID: <i>CallID</i>, Metric: <i>metricName</i>,
Value: <i>metricValue</i>, Units : { native: <i>unitcode</i>,
unit: <i>userunitcode</i>, label: <i>label</i>} }}</div>
<div><br>
</div>
<div>So I can create a Promise and put the Accept function
agains the (random) <i>CallID</i> on an object, (and a timeout
that calls reject) -so when the result comes in I can call the
accept. <br>
</div>
</div>
</blockquote>
<br>
If the asynchronous nature isn't hidden (i.e. caller needs to use
async/await tags) and using the async getters is an alternative to
the pattern subscription scheme, that would be OK for inclusion. It
adds another way to subscribe, that may be better for some
applications. Keep in mind a page/fragment's getter subscriptions
then also need to be unsubscribed on unloading the page/fragment.<br></div></blockquote><div><br></div><div>Yep - definitely worked out that the async nature can't be hidden, it seems it's just not an option. </div><div>Hmm.. unsubscribe - ouch - this might be 'fun'. Will see how it goes. The values need to be cleared from the metrics[] array indicating they need to be subscribed again.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div>
<br>
<blockquote type="cite">
<div dir="ltr">
<div>It still doesn't get over the need for plugins to either
subscribe to the metrics they want to access through
metrics[]... or use the ametrics[] collection in an async
function. Having a tag (as you mentioned) that says which
metrics to subscribe to would be at least backwards
compatible. I guess we could make it so that if a plugin was
searched for such a tag and none existed, we could subscribe
all?</div>
</div>
</blockquote>
<br>
Yes, and we could add an API version attribute, to be able to
identify receivers that expect to have direct access to all metrics.
That way we still enable a new receiver to be created that really
doesn't need metrics (or does all subscriptions through the async
getters). Something like…<br>
<br>
<font face="monospace"><div class="receiver"><br>
→ auto subscription to "metrics/#" if no explicit "metrics/…"
subscriptions present<br>
<br>
<div class="receiver" data-apiversion="2"><br>
→ only process explicit subscriptions</font></div></blockquote><div>I very much like the apiversion idea: Easy to check for.</div><div><br></div><div>Also, I've been looking at the current subscription scheme - with a tag lookup. The way I currently implement subscriptions for the metrics is that I use a 'slot' per connection like the 'modified' flag which indicates that a metric is subscribed. I'm wondering if it would be ok if when the particular metrics/* namespace comes in, if I could divert that to using the same method I have now then it would keep things working quite quickly... would that work for you?</div><div> <br></div><div>//.ichael</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><br>
<br>
Regards,<br>
Michael<br>
<br>
<br>
<blockquote type="cite">
<div dir="ltr">
<div><br>
</div>
<div>//.ichael</div>
<div><br>
</div>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Sun, 11 Dec 2022 at
19:54, Michael Balzer <<a href="mailto:dexter@expeedo.de" target="_blank">dexter@expeedo.de</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div> Michael,<br>
<br>
yes, while async getters seem to be possible by some JS
voodoo, they probably won't work without changes to the
applications.<br>
<br>
I also don't think they would form an application code
pattern we should encourage, as they would try to hide
asynchronous operations and would lead to each individual
metric needing to be requested (at least initially) by a
separate async call.<br>
<br>
Instead, please reconsider:<br>
<br>
<blockquote type="cite"> Btw, in case you didn't see this
already: I implemented an auto subscription scheme for
the 'stream' notifications -- these are by default very
transmission intense and can cause substantial load on
the module side as well. These subscriptions are managed
automatically for all components and plugins by the
framework (which btw also takes care of initializing all
fragments added in the '#' container).</blockquote>
<br>
I designed this subscription scheme to follow the MQTT
topic subscription scheme and be usable for any kind of
subscription. Different data sources can be identified by
the root topic. For notifications, it's `notify/`, for
metrics, we can naturally assign `metrics/`. A
subscription pattern `metrics/v/p/#` would for example
subscribe to all `v.p.*` metrics.<br>
<br>
Auto subscribing & unsubscribing is managed by the
framework via the `data-subscriptions` attribute of a
`.receiver`.<br>
<br>
Examples:<br>
<ul>
<li><a href="https://docs.openvehicles.com/en/latest/components/ovms_webserver/docs/notifications.html" target="_blank">https://docs.openvehicles.com/en/latest/components/ovms_webserver/docs/notifications.html</a></li>
<li><a href="https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/tree/master/plugins/retools" target="_blank">https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/tree/master/plugins/retools</a><br>
</li>
</ul>
<br>
Btw, if (!) we keep the units dictionary subscription
necessity, that could be a subscription to `units/#`.<br>
<br>
Regards,<br>
Michael<br>
<br>
<br>
<div>Am 08.12.22 um 04:29 schrieb Michael Geddes:<br>
</div>
<blockquote type="cite">
<div dir="ltr">
<div>I've implemented a way of having user units of
metrics come through (I have metrics_user[]
metrics_label[] and metrics_all[] implemented).. </div>
<div><b>however as far as dynamic subscription to
metrics goes, I now believe I can't do what I want
in a backwards compatible way.</b><br>
</div>
<div><br>
</div>
<div>This is where I'm at:</div>
<div><br>
</div>
<div>I<span style="background-color:rgb(255,255,255);font-family:Arial,Helvetica,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;color:rgb(34,34,34);float:none;display:inline"> haven't
used Promises before or async/wait etc, so in my </span>naivity,
I had (mistakenly it seems) thought I could define a
function taking a <i>metric code</i> that</div>
<div>* Sends a command to the websocket eg <i>metric
fetchsub 1234 v.p.trip</i></div>
<div>* Waits for the result coming in over the
web-socket or times out</div>
<div>* Returns the result to the user <b>directly</b></div>
<div>so <i>metric['</i> <i>v.p.trip</i><i>'] </i>
(or whatever) could have an accessor function that
(for unsubscribed metrics) silently fetched and
subscribed to the metric over the websocket and
returned the value.</div>
<div><br>
</div>
<div>I have actually implemented the fetching bit
mostly .. (a Promise resolve call-back is put in a
collection against a random id and when the event
comes back it uses the id to grab the promise
function and resolve with the result - and yes it
has a timeout) ... except that in the end, the
javascript still requires a Promise to be created
that needs to execute its result as a call-back. <span style="background-color:rgb(255,255,255);font-family:Arial,Helvetica,sans-serif;font-size:small;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;color:rgb(34,34,34);float:none;display:inline">I
also believe I now understand why that is not
possible, and that </span>fundamentally the only
way of doing async stuff at all ends up in some kind
of call back (via a Promise directly or an async
function Promise)... and that the only exceptions to
this are within an async function (which in the end
still returns a Promise).</div>
<div><br>
</div>
<div>This makes blocking on a metric['v.p.trip']
proxy get; function not possible afaict. Unless
somebody knows a mechansim that I could use?
(outside of an async function, of course)</div>
<div><br>
</div>
<div>I have implement the subscription model for
metrics[] (which supports, for example, v.p.* ) ..
but without the auto-subscription it is going to be
less useful for plugins as far as backwards
compatibility goes! </div>
<div><br>
</div>
<div>you could have a call like this:</div>
<div> applyMetric('v.p.trip', (value) => { ...
put the value somewhere } )</div>
<div><br>
</div>
<div><br>
</div>
<div><br>
</div>
<div>//.ichael</div>
<div><br>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Sat, 3 Dec 2022
at 02:29, Michael Balzer <<a href="mailto:dexter@expeedo.de" target="_blank">dexter@expeedo.de</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div> Michael,<br>
<br>
the unit conversion JS code scheme is fine. Btw,
you can optimize convert to…<br>
<br>
<font face="monospace"> convert = function
(from, to, value) {<br>
return (</font><font face="monospace"><font face="monospace"><font face="monospace">unit_conversions[from
+ ">" + to] || </font></font><font face="monospace"><font face="monospace"><font face="monospace">unit_conversions.native</font></font></font>)(value);<br>
}<br>
</font></div>
</blockquote>
<div>Yeah - I'm assuming that the gain from not
looking up unnecessarily is lost from all the
checking. Got it.</div>
<div><br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><font face="monospace"> </font>
<div><br>
</div>
<blockquote type="cite">I knew we had to keep
the default webstream as it was. I was
thinking of having a different websocket Uri
to trigger filtered mode (starting without
sending all units).<br>
</blockquote>
<blockquote type="cite">Especially, I was also
considering the plugins that run from the '#'
container that may not know the container had
switched to user units! (so I'm not sure about
option a.), so from what I can tell, the base
metrics[] needs to maintain native units imho.
This is also why I was looking at the
'auto-subscribe' idea since the outside
container doesn't know which metrics a plugin
might use, and a plugin wouldn't know to
subscribe to the messages.</blockquote>
<br>
I think plugins will need to be updated anyway,
as will all our standard pages & components,
as up to now all units have been fixed in the
UI.<br>
<br>
In both approaches, all metrics displays (simple
markup, tables, charts) will need to be reworked
to use the user units. Only the basic markup
type displays could partially be modified
automatically (by walking through their '.unit'
elements), but any extended use, even the range
& energy displays in the dashboard's speed
gauge, will need a config-aware approach.<br>
<br>
Charts will need to fully reconfigure, as unit
labels are used within different chart features,
and axis limits & plotbands will need to be
adjusted. For this, scripts can subscribe to a
new 'msg:units' event sent when a
(re-)configuration of units is received.<br>
</div>
</blockquote>
<div>Yeah - I've got some classes so that different
cars can specify all the ranges in native units
and it will generate code for the current user
units. I've already put this into use for all
vehicle classes that return a custom guage
configuration.</div>
<div><br>
</div>
<div> At the moment it is still static code and
we'll need to sink on a (not yet
implmeneted) untits changed event to reload it..
but it would be simple enough to change the code
generated to be dynamic (especially that we now
have that conversion function). Even just having
the user refresh the page is better than nothing
at the moment (it's not like the user is going to
be changing the units all the time).</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div> <br>
Btw, in case you didn't see this already: I
implemented an auto subscription scheme for the
'stream' notifications -- these are by default
very transmission intense and can cause
substantial load on the module side as well.
These subscriptions are managed automatically
for all components and plugins by the framework
(which btw also takes care of initializing all
fragments added in the '#' container).<br>
<br>
<blockquote type="cite">
<div>We could maintain a units collection
exactly as above with some proxy arrays to
get at values without exceptions. For eg: </div>
<div>m.label["v.p.speed"] could look up the
units_ collection being maintained and
return blank if the entry doesn't exist.
Then</div>
<div>m.value["v.p.speed"] would give the user
unit and m.nativevalue["v.p.speed"] the
native value. The latter two would use the
metrics[] array or whatever mechanism we
had. We could add m.text["v.p.speed"] that
would give a text version with the value and
unit if it had one.</div>
</blockquote>
<br>
That leads us to another option: we could keep
the metrics transmission in native values, add
the units dictionary and provide all conversions
in Javascript using this proxy getter scheme.<br>
</div>
</blockquote>
<div><br>
</div>
<div>Yep - already decided to do that. It makes more
sense. At the moment I'm also implementing a way
of starting off with no metrics supplied and then
adding in which ones we need. Probably the JS is
the bit I need to work out on that.</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div> <br>
That would keep the current metrics[] access
scheme intact and unchanged, so all current
frontend code & plugins would continue to
work, using the native values as before.<br>
<br>
The new proxy getters then can be used as the
new way to access metrics by anyone interested
in using user units, and we can go ahead by
applying this to the standard pages and
components.<br>
<br>
This in combination with the 'msg:units' event
to signal reconfiguration should provide all we
need.<br>
<br>
We can even easily combine this with providing a
command or socket URL / parameter to switch the
metrics into user mode. The standard web
frontend won't need this then, but it would make
using user units easy for devices without
Javascript support.<br>
<br>
Regards,<br>
Michael<br>
<br>
<br>
<div>Am 28.11.22 um 00:36 schrieb Michael
Geddes:<br>
</div>
<blockquote type="cite">
<div dir="ltr">Solved a couple of things.
<div>I have a 'unit conversion' code - which
I current have put into a separate cpp
file along with the two other C++
conversion functions.</div>
<div>I wanted to do it this way so they are
all in there together. (Does this make
sense to do?).</div>
<div><br>
</div>
<div> <font face="monospace"> mi_to_km =
function(mi) { return mi * 1.609347; }<br>
km_to_mi = function(km) { return km *
0.6213700; }<br>
pkm_to_pmi = function(pkm) { return
pkm * 1.609347; }<br>
pmi_to_pkm = function(pmi) { return
pmi * 0.6213700; }<br>
const feet_per_mile = 5280;<br>
var unit_conversions = {<br>
"native": function
(value) { return value;},<br>
"km>miles":
km_to_mi,<br>
"km>meters":
function (value) { return value*1000;
},<br>
"km>feet":
function (value) { return
km_to_mi(value) * feet_per_mile; },<br>
......<br>
"percent>permille":
function (value) { return value*10.0; },<br>
"percent>percent":
function (value) { return value*0.10; }<br>
}<br>
convert_function = function (from, to)
{<br>
var fn = undefined;<br>
if (from !== to && to !==
"")<br>
fn = unit_conversions[from +
">" + to];<br>
if (fn == undefined)<br>
fn = unit_conversions.native;<br>
return fn;<br>
}<br>
convert = function (from, to, value) {<br>
var fn = convert_function(from, to);<br>
return fn(value);<br>
}<br>
</font></div>
<div><br>
</div>
<div>The other problem of looking at the uri
of the websocket I have solved by creating
a 'SocketCreator' MgHandler class in
the MG_EV_WEBSOCKET_HANDSHAKE_REQUEST
event (and looks at the uri)... that waits
for the</div>
<div>MG_EV_WEBSOCKET_HANDSHAKE_DONE and
deletes itself.</div>
<br>
int OvmsSocketCreator::HandleEvent(int ev,
void *p)<br>
{<br>
if ( ev != MG_EV_WEBSOCKET_HANDSHAKE_DONE)<br>
return ev;<br>
// new websocket connection<br>
MyWebServer.CreateWebSocketHandler(m_nc,
m_socket_type );<br>
m_nc = NULL;<br>
delete this;<br>
return 0;<br>
}<br>
<div><br>
</div>
<div>Thoughts?</div>
<div><br>
</div>
<div>//.ichael</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Sun, 27
Nov 2022 at 07:18, Michael Geddes <<a href="mailto:frog@bunyip.wheelycreek.net" target="_blank">frog@bunyip.wheelycreek.net</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div dir="ltr">
<div dir="auto">
<div dir="auto">I knew we had to keep
the default webstream as it was. I
was thinking of having a different
websocket Uri to trigger filtered
mode (starting without sending all
units).. Though I am struggling with
how to get and then pass the Uri
information into the web socket
constructor! The event that
currently creates it doesn't seem to
have access to the Uri. (see below -
p is NULL for HANDSHAKE_DONE).</div>
<div dir="auto">
<div style="color:rgb(212,212,212);background-color:rgb(30,30,30);font-family:Consolas,"Courier New",monospace;line-height:19px;white-space:pre-wrap"><div> <span style="color:rgb(197,134,192)">case</span> <span style="color:rgb(86,156,214)">MG_EV_WEBSOCKET_HANDSHAKE_REQUEST</span>:</div><div> {</div><div> <span style="color:rgb(86,156,214)">struct</span> <span style="color:rgb(78,201,176)">http_message</span> <span style="color:rgb(86,156,214)">*</span><span style="color:rgb(156,220,254)">hm</span> = (<span style="color:rgb(86,156,214)">struct</span> <span style="color:rgb(78,201,176)">http_message</span> <span style="color:rgb(86,156,214)">*</span>) <span style="color:rgb(156,220,254)">p</span>; // how to pass uri info to the event below!?</div><div> }</div><div> <span style="color:rgb(197,134,192)">break</span>;</div><div> <span style="color:rgb(197,134,192)">case</span> <span style="color:rgb(86,156,214)">MG_EV_WEBSOCKET_HANDSHAKE_DONE</span>:<span style="color:rgb(106,153,85)"> // new websocket connection</span></div><div> {</div><div> <span style="color:rgb(156,220,254)">MyWebServer</span>.<span style="color:rgb(220,220,170)">CreateWebSocketHandler</span>(<span style="color:rgb(156,220,254)">nc</span>);</div><div> }</div><div> <span style="color:rgb(197,134,192)">break</span>;</div>
</div>
</div>
<div dir="auto"><br>
</div>
<div dir="auto"><br>
</div>
<div dir="auto">Especially, I was also
considering the plugins that run
from the '#' container that may not
know the container had switched to
user units! (so I'm not sure about
option a.), so from what I can tell,
the base metrics[] needs to maintain
native units imho. This is also why
I was looking at the
'auto-subscribe' idea since the
outside container doesn't know which
metrics a plugin might use, and a
plugin wouldn't know to subscribe to
the messages.</div>
<div dir="auto"><br>
</div>
<div>I do like the separate units
description message - though we
would probably need to add the
'native' if we want to do
conversions.</div>
<font face="monospace"><font face="monospace"><br>
{ units: {<br>
"v.p.speed": { </font></font><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace">code: "kmph",
<b>native "kmph",</b> </font></font>label:
"km/h" }, …</font></font><br>
<div><br>
</div>
<div>We could maintain a units
collection exactly as above with
some proxy arrays to get at values
without exceptions. For eg: </div>
<div>m.label["v.p.speed"] could look
up the units_ collection being
maintained and return blank if the
entry doesn't exist. Then</div>
<div>m.value["v.p.speed"] would give
the user unit and
m.nativevalue["v.p.speed"] the
native value. The latter two would
use the metrics[] array or whatever
mechanism we had. We could add
m.text["v.p.speed"] that would give
a text version with the value and
unit if it had one.</div>
<div dir="auto"><br>
</div>
<div>I had contemplated the idea of
providing a JavaScript unit
conversion and was working around
it. Downside is it's a third set of
conversion functions to maintain...
On the other hand using that we
could just keep the metrics being
sent as it is now, have the groups
sent as you proposed (along with the
native unit code) , and have the
above m.value[] proxy collection use
a 'touser' function assigned to the
units_ collection above that
provided native to user conversion.</div>
<div>
<div dir="auto"> </div>
<div>We could send a javascript
library constructed with just the
necessary functions for the
required conversions of native to
user (or the whole lot..
whichever). .</div>
<div>--</div>
<font face="monospace">var
conversions = {</font></div>
<div><font face="monospace"> unit:
function ( value) { return value }<br>
km_miles: function (value) {
return value * 0.6213700; }</font></div>
<div><font face="monospace"> }</font>
<div>We could perform the lookup
when constructing the units and
assign the touser property. (And
have a 'unit' function that does
no conversion).</div>
</div>
<div dir="auto"><br>
//.ichael <br>
<br>
<div class="gmail_quote" dir="auto">
<div dir="ltr" class="gmail_attr">On
Sat, 26 Nov 2022, 10:43 pm
Michael Balzer, <<a href="mailto:dexter@expeedo.de" target="_blank">dexter@expeedo.de</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div> The metrics subscription
scheme is an option, and the
auto-subscribe feature via a
getter is a nice idea. But I
wouldn't apply that to metrics
value conversions and units.<br>
<br>
Also we would still need the
current set of metrics to be
subscribed by default, as
there are also non Javascript
devices (e.g. smart buttons,
Wifi displays) reading the
WebSocket stream.<br>
<br>
My thoughts on this so far:<br>
<br>
Basically the web UI, as any
frontend, should adapt to unit
configurations seamlessly. The
web UI includes many command
outputs, which already
automatically switch units as
configured.<br>
<br>
For all practical purposes,
the web UI needs to interact
with users in their preferred
units. Only some plugins and
functions will need certain
values in metric (native)
units for calculations, and
these will also need a simple
way to convert calculation
results back to user units for
displaying. So I think we need
to provide the unit
configuration and value
conversion tools in the web
framework as well.<br>
<br>
Proposal:<br>
<br>
a) We provide a config option
and a WebSocket command to
switch the WebSocket metrics
transmission mode to user /
native units. To keep plugin
compatibility, the default is
'native'.<br>
<br>
b) We introduce a separate
units dictionary object
containing the user units for
both metrics and the unit
groups in their code &
label representation. The
units dictionary only needs to
be sent initially, when new
metrics are registered, when
the metrics mode is changed
for the current connection,
and when some user unit
configuration is changed,
keeping the bandwidth and
processing requirements low.<br>
<br>
The units dictionary can
combine both metrics and group
units, as the unit group names
are fully distinct from the
metrics namespace. The
transport scheme could be:<br>
<br>
<font face="monospace"><font face="monospace">{ units:
{<br>
"v.p.speed": { </font></font><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace">code:
"kmph", </font></font>label:
"km/h" }, …<br>
"</font></font><font face="monospace"><font face="monospace"><font face="monospace">units.distance":
{ </font></font></font><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace">code:
"</font></font></font></font></font></font></font><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace">miles</font>", </font></font>label: "M" }, …<br>
}<br>
</font></font></font><br>
</font></font>c) In the web
framework, accessing units
should be as simple as
possible and avoid throwing
exceptions for undefined
entries, so we could e.g.
split these into separate code
& label objects:<br>
<font face="monospace"><font face="monospace"><br>
units["v.p.speed"]
= "km/h" //
consistently accompanies
metrics["v.p.speed"]<br>
</font></font><font face="monospace"><font face="monospace"><font face="monospace">unit</font></font></font><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace"><font face="monospace">codes</font></font></font>["v.p.speed"]
= "kmph"<br>
<br>
</font></font></font><font face="monospace">units["units.distance"]
= "M"</font><br>
<font face="monospace">unitcodes["units.distance"]
= "miles"</font><br>
<br>
…or provide a getter that
tests for the key existence
and returns an object with
empty fields as necessary.<br>
<br>
With this, all metrics
displays can easily be changed
to display the actual unit
labels instead of using fixed
strings.<br>
<br>
d) To provide value conversion
we implement UnitConvert() in
Javascript plus some wrappers
that automatically look up the
unit for a given metrics/group
name and do the conversion
to/from native units,
something like…<br>
<br>
<font face="monospace">var
speed_kph =
toNativeValue("v.p.speed");
// optional second arg to
convert any data<br>
</font><font face="monospace"><font face="monospace"><font face="monospace">var
speed_kph =
metrics_native["v.p.speed"];
// using a getter<br>
<br>
</font></font>var
trip_display =
toUserValue("units.distance",
1234);<br>
<br>
</font><br>
Plugins for
scientific/technical
applications that depend on
native (metric) units can use
the new metrics transmission
mode control command to force
native mode. Or they can
choose to migrate from
"metrics[]" to
"metrics_native[]".<br>
<br>
The metrics mode config option
can come with a note informing
users that there may be some
old plugins not compatible
with non-native units. They
can then check their plugins
for this and make an informed
decision on wether to enable
user units and/or wether to
install a specific plugin.<br>
<br>
Thoughts, comments?<br>
<br>
Regards,<br>
Michael<br>
<br>
<br>
<div>Am 25.11.22 um 03:13
schrieb Michael Geddes:<br>
</div>
<blockquote type="cite">
<div dir="ltr">
<div dir="ltr">I have an
idea which might reduce
traffic for maintaining
the metrics[] array in
the browser and cope
with the user units.</div>
<div dir="ltr">I'll start
by saying I'm not a JS
developer per se.. so a
newb in JS really.
Still, it's mainly just
another language so ..
we'll give it a go. <br>
<div><br>
</div>
<div>Firstly:</div>
<div>* Implement the
'changed' filters as
below for the
web-socket.. for both
normal and 'user'
values.</div>
<div>* Add a function
that subscribes to a
value (and returns the
current value of
it)..including to
'user'
value/unitlabel.</div>
<div><br>
</div>
<div>Subscribing the
normal way to the
metrics over the
websocket would have
the normal effect..
but we would have a
new way that would
subscribe in a
filtered way.</div>
<div><br>
</div>
<div>I've had a little
play with the Proxy
object .. so at least
I know this should
work:</div>
<div><br>
</div>
<div>Have a metrics_
array that is the real
associative array for
metrics[] and then
define a Proxy that
has (at the least)
'get' and 'has'
defined (giving us the
ability to overload <i>metrics['prop']</i>
and <i>"prop" in
metrics operations</i>).</div>
<div><br>
</div>
<div>The <i>get </i>function
would return the
underlying value if it
exists in the <i>metrics_ </i>array
(which is maintained
through the websocket
from currently
subscribed values in
the current manner). </div>
<div>If the value is not
in the <i>metrics_</i> array
- it would then do a
subscribe+query on the
websocket getting the
current value and
adding it into the <i>metrics_</i> container.
If it was unavailable
then it would put <i>undefined</i> into
the array.<br>
</div>
<div>The 'has' would do
the get() and return
true if the value was
not == <i>undefined</i>. </div>
<div><br>
<div>For the 'query
the websocket' bit,
I'm assuming I would
be working with
promises or futures
or some such: I'll
do the research and
do it properly
unless somebody can
help me out with it.
That's the bit I was
going to work on
next for the
proof-of-concept.</div>
<div><br>
</div>
<div>Any immediate
thoughts? Dangers?</div>
<div><br>
</div>
<div>I also noticed
there was a bit that
went through html
element properties
and looked for
metrics .. this
could be used to
bulk subscribe to
any metric values
required there.</div>
<div><br>
</div>
<div>//.ichael</div>
<div><br>
</div>
</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On
Thu, 17 Nov 2022 at
07:52, Michael Geddes
<<a href="mailto:frog@bunyip.wheelycreek.net" rel="noreferrer" target="_blank">frog@bunyip.wheelycreek.net</a>> wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div dir="ltr">
<div dir="ltr">Yeah,
ok.<br>
</div>
<div dir="ltr"><br>
</div>
<div>I will get all
the other 'user
unit' stuff done
as a line in the
sand, and then
move to working
out the web
stuff. I'm still
finding my way
though all the
client side
javascript, which
looks very cool..
but I've not
really done jQuery
before (just
enough to
recognise it).</div>
<div><br>
</div>
<div>Subscribing to
metrics
with/without user
units makes a lot
of sense.
Obviously the
default needs to
be 'Subscribe to
all metrics but
not user units' to
maintain
compatibility...
but I was also
thinking it might
be nice if we
could filter down
even the normal
subscribed events.</div>
<div>We could have:</div>
<div>* Web socket
command to filter
units (flag on
websocket to say
'filtered' + flag
bitset on each
metric similar to
'dirty')<br>
</div>
<div>Then either:</div>
<div>* Web socket
command to turn on
user units (single
flag on that
websocket)</div>
<div>or </div>
<div>* Web socket
command to turn on
user units for
specific metrics
(flag bitset on
each metric)</div>
<div><br>
</div>
<div>A parameter to
the URI for the
websocket could
start the socket
in 'filtered' mode
to avoid the
initial rush of
metrics.</div>
<div><br>
</div>
<div>This could
drastically reduce
traffic and time
for the metrics
command to
execute. It would
be possible to
also check (on a
'filtered'
websocket) for any
changes to metrics
for that websocket
slot before
queueing the
'metric update'
socket command.</div>
<div><br>
</div>
<div>//.ichael</div>
<div><br>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On
Thu, 17 Nov 2022
at 00:35,
Michael Balzer
<<a href="mailto:dexter@expeedo.de" rel="noreferrer" target="_blank">dexter@expeedo.de</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div> Michael,<br>
<br>
I don't have
much spare
time
currently,
just some
quick first
comments: it's
important to
implement this
as lightweight
as possible,
both in terms
of network
load and
client CPU
& memory
requirements.
Some devices
already have
issues, which
can be seen by
the "websocket
overflow"
messages. The
web UI also
should stay
usable via
cellular.<br>
<br>
My impression
is the new
scheme, while
only slightly
raising the
client
requirements,
adds
substantially
to the network
requirements.<br>
<br>
An option
could be to
separate the
units -- or
more, back
when
implementing
this I thought
about
separating the
names later
on. Another
question is if
we normally
generally need
both the
native and the
converted
values in the
web UI. We
maybe could
provide an
option to
switch to
converted
values, or add
an option to
retreive or
subscribe to a
set of
converted
metrics on
demand.<br>
<br>
Standard
plugins like
ABRP and
PwrMon rely on
getting metric
(native)
units, and
there probably
are non-public
plugins, e.g.
for
engineering
&
scientific
projects, that
depend on
metric units
to do their
calculations
and don't need
anything else.
We shouldn't
make life
harder for
these
applications
without good
reason.<br>
<br>
Regards,<br>
Michael<br>
<br>
<br>
<div>Am
15.11.22 um
01:26 schrieb
Michael
Geddes:<br>
</div>
<blockquote type="cite">
<div dir="ltr">
<div dir="ltr">If
you're ok with
the [default]
option I'll
stick with
that. I mean
in some ways
it would be
nice to have a
button choice</div>
<div dir="ltr">metric
| usa | europe
| asia |
custom etc
and I kind of
considered
something like
that but
figured it's
only a handful
of choices..
and it's an
embedded
device.. so
simpler is
better.</div>
<div dir="ltr"><br>
</div>
<div>On a
related note -
I was thinking
how it would
be nice if the
dashboard
(etc) had
access to the
'user' units,
so went
hunting down
that little
rabbit hole.
Quite a nice
mechanism with
the web socket
updating the
"metrics"
object in the
UI. </div>
<div>This is a
snippet of one
idea, which is
that for any
metric that
has the
possibility of
a user unit,
we set the
extra values
of the metric
with '#unit'
and '#user'
appended - see
below. (I've
chosen '#'
arbitrarily..
but it could
be '/' or ':'
or '>' but
maybe not '.'
)</div>
<br>
v.p.odometer#unit: "M"<br>
v.p.odometer#user: 6754.91<br>
v.p.satcount:
13<br>
v.p.speed: 0<br>
v.p.speed#unit: "km/h"<br>
v.p.speed#user: null<br>
<b>v.p.trip:
28</b><br>
<b>v.p.trip#unit:
"M"<br>
v.p.trip#user:
17.3984</b>
<div><br>
</div>
<div>Then we
can use this
in the dials
to populate
the values and
captions! (not
that I like
Miles).</div>
<div>I</div>
<div>
<div><br>
</div>
<div><img alt="image.png" width="217" height="136"><br>
</div>
<div><br>
</div>
<div>The other
(similar) way
was to have
something like
the following:</div>
<div>"v.p.trip#user"
: { "value":
17.3984,
"unit": "M" }</div>
<div>It
wouldn't make
the total
message any
shorter..
soo.. dunno.</div>
<div><br>
</div>
<div>There's
also some
complications
with setting
up the dials
(for min/max
values) - like
for the speed.</div>
<div><br>
</div>
<div>Notice
also that I'm
returning null
for undefined
values. It's
nice - but I'm
not sure how
javascript
handles null
when used /
printed etc.</div>
<div><br>
</div>
<div>//.ichael</div>
<div><br>
</div>
<div>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Sun, 13 Nov 2022 at 21:06, Michael Balzer <<a href="mailto:dexter@expeedo.de" rel="noreferrer" target="_blank">dexter@expeedo.de</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div> Michael,<br>
<br>
looks good.<br>
<br>
I think having
an explicit
'default'
option is
better than
taking the
'Metric'
equivalent for
that, as in
your example
you already
show unit
alternatives
within the
metric system
to support
different
scalings (kW /
W, kWh / Wh).
(Btw… waiting
for someone to
miss
Horsepower
& BTU here
;-))<br>
<br>
@Patrick, I
think that
also answers
your implicit
question:<br>
<blockquote type="cite">
<pre>The default button makes it unclear what the actual setting is.
</pre>
</blockquote>
<br>
The default
(native unit)
is always
metric, but
you may have a
mix of
scalings, as
we try to find
the one that
fits best for
the given
application
when defining
a metric. For
example the
current
driving energy
consumption is
stored
natively in
Wh/km, while
the energy
used or
regenerated is
in kWh, and
the odometer
& trip
counters are
in km, while
the altitude
ist in m.<br>
<br>
Regards,<br>
Michael<br>
<br>
<br>
<div>Am
13.11.22 um
08:42 schrieb
Michael
Geddes:<br>
</div>
<blockquote type="cite">
<div dir="ltr">Greetings,<br>
<div>so this
is my idea of
being able to
select which
units various
groups use (in
addition to
Distance).</div>
<div>This can
be then
accessed by
the special
'user' unit
code. (or
'metrics list
-u ' )</div>
<div>The idea
of [Default]
selection
below simply
means storing
the value to
blank -
meaning use
whatever unit
the particular
metric uses.
The other idea
I had was to
actually
default it to
the equivalent
of 'Metric'
special unit
code and not
have the
[Default]
button.</div>
<div><br>
</div>
<div><br>
</div>
<img alt="image.png" width="472" height="395"><br>
<div><br>
</div>
<div>Currently
I've made it
so that if
there are more
than 3 choices
other than
[default] that
it uses the
choice/combo
box rather
than the Radio
buttons. (ie
this list is
auto-generated
from the
Metric Units
table and the
Metric Groups
table).</div>
<div><br>
</div>
<div>Thoughts
/ comments?</div>
<div><br>
</div>
<div>//.ichael </div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Sat, 12 Nov 2022 at 17:35, Michael Geddes <<a href="mailto:frog@bunyip.wheelycreek.net" rel="noreferrer" target="_blank">frog@bunyip.wheelycreek.net</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div dir="ltr">
<div dir="ltr"><a href="https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/pull/771" rel="noreferrer" target="_blank">https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/pull/771</a><br>
<div><br>
</div>
<div>I'm
hoping this
P/R is ok in
this form
(made of 5
separate commits).</div>
<div><br>
</div>
<div>I will
have a look at
implementing
the "user"
unit code.
The base for
how it
would work is
already a part
of the above
pull request.
I'll just look
at the module
configuration
for distance.</div>
<div><br>
</div>
<div>The
'power
consumption'
is one where
it's not just
a check-box..
there're 5
possible
choice!</div>
<div><br>
</div>
<div>I should
also add 'bar'
for pressure
given that for
some reason
that's still a
thing people
want.</div>
<div><br>
</div>
<div>//.ichael</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Sat, 12 Nov 2022 at 16:24, Michael Balzer <<a href="mailto:dexter@expeedo.de" rel="noreferrer" target="_blank">dexter@expeedo.de</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div> I think
this is pretty
decent &
complete now.<br>
<br>
I also like
the approach
of the 'user'
unit code.
Moving all
user unit
prefs into the
module
configuration
is an old
todo.
Currently only
the distance
unit is
defined at the
module side,
temperature
and pressure
are App prefs.<br>
<br>
Regards,<br>
Michael<br>
<br>
<br>
<div>Am
11.11.22 um
09:54 schrieb
Michael
Geddes:<br>
</div>
<blockquote type="cite">
<div dir="ltr">Ok
- so here's
what I have
implemented
for Duktape
and Metrics.
(I added
IsDefined() as
well).
<div>Any
thoughts on
this?<br>
<div><br>
<div>Noting</div>
<div>
OvmsMetrics.Float(
{metric} )
-> Outputs
metric as
float (same)</div>
<div>
OvmsMetrics.Float(
{metric},
{unit}) ->
Outputs metric
as float
converted to
given unit
(new)</div>
<div>
OvmsMetrics.Value(
{metric} )
-> Outputs
Metric in
native value
(same)</div>
<div>
OvmsMetrics.Value(
{metric} ,
false) ->
Outputs Metric
as string and
no units
(same) </div>
OvmsMetrics.Value(
{metric} ,
{unit}) ->
Outputs Metric
converted to
given unit as
native value.
(new)
<div>
OvmsMetrics.Value(
{metric} ,
{unit}, false
) ->
Outputs Metric
converted to
given unit as
string
including any
unit
specifier.
(new)
<div>also
OvmsMetric.GetValues(
{metric}
[,{unit}] [,
{converted} ]
) Adds
similar
behaviour to
Value() above.</div>
<div>also the
special units
'<b>imperial</b>'
and '<b>metric</b>'
will convert
to the
associated
imperial /
metric version
of the units
as
appropriate.</div>
<div><br>
<div><font face="monospace">(function()
{<br>
dump =
function
(metric) {
print( metric+
" ["+(typeof
metric)+"]\n"
); }<br>
dump_obj =
function (obj
) {<br>
print('---
Object
----\n')<br>
for (var
k in obj) {<br>
xk =
obj[k];<br>
print(
k+':'+ xk + '
['+typeof xk+
"]\n");<br>
}<br>
}<br>
dump(OvmsMetrics.Value("xiq.v.trip.consumption"));<br>
dump(OvmsMetrics.Value("xiq.v.trip.consumption",
false));<br>
dump(OvmsMetrics.Value("xiq.v.trip.consumption","kmpkwh"));<br>
dump(OvmsMetrics.Value("xiq.v.trip.consumption",
"mipkwh",
false));<br>
dump(OvmsMetrics.AsFloat("xiq.v.trip.consumption"));<br>
dump(OvmsMetrics.AsFloat("xiq.v.trip.consumption","kmpkwh"));<br>
dump(OvmsMetrics.Value("xiq.v.trip.consumption","imperial"))<br>
dump(OvmsMetrics.Value("xiq.v.trip.consumption","imperial",
false))<br>
dump_obj(OvmsMetrics.GetValues("trip",
"metric"))<br>
dump_obj(OvmsMetrics.GetValues("trip",
"imperial",
false))<br>
})();<br>
</font></div>
<div><br>
</div>
<div>With this
output:</div>
<div>
<div>
<pre id="m_4886991932006770610m_1082575795986022020m_-6437764485757861817m_1446710767644746708m_3389478097269637711m_-3595551468962657953m_-358274377416053507m_-7644593744426345619m_-5441616086226233372m_8405494616978842232m_-5904723395924573806m_1733173679174480992m_-138117451584655546m_5484224439251412587gmail-output" style="box-sizing:border-box;overflow:auto;font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;font-size:13px;padding:9.5px;margin-top:0px;margin-bottom:10px;line-height:1.42857;color:rgb(0,34,0);word-break:break-all;background-color:rgb(245,245,245);border:1px solid rgb(204,204,204);border-radius:4px;height:406px;white-space:pre-wrap">19.2308 [number]
19.2308 [string]
5.2 [number]
3.23112mi/kWh [string]
19.2308 [number]
5.2 [number]
309.49 [number]
309.49Wh/mi [string]
--- Object ----
v.p.trip:13 [number]
xiq.e.trip:0 [number]
xiq.e.trip.energy.recuperated:0 [number]
xiq.e.trip.energy.used:0 [number]
xiq.v.trip.consumption:19.2308 [number]
--- Object ----
v.p.trip:8.07781M [string]
xiq.e.trip:0M [string]
xiq.e.trip.energy.recuperated:0kWh [string]
xiq.e.trip.energy.used:0kWh [string]
xiq.v.trip.consumption:309.49Wh/mi [string]</pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Wed, 9 Nov 2022 at 05:47, Michael Geddes <<a href="mailto:frog@bunyip.wheelycreek.net" rel="noreferrer" target="_blank">frog@bunyip.wheelycreek.net</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div dir="ltr">Yeah
- I like
HasValue. I
implemented
IsDefined()
but I will
rename it..
that's a much
clearer name.
<div><br>
</div>
<div>Another
thought. How
about if we
did this (but
also with
GetValues() as
well - see the
special values
below) </div>
<div><br>
<div>OvmsMetrics.Value("xiq.v.trip.consumption",
true) -> <span style="background-color:rgb(245,245,245);color:rgb(0,34,0);font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;font-size:13px;white-space:pre-wrap">17.0582</span><span style="background-color:rgb(245,245,245);color:rgb(0,34,0);font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;font-size:13px;white-space:pre-wrap"> (Number)</span><br>
</div>
<div>
<div>OvmsMetrics.Value("xiq.v.trip.consumption",
false)
-> <span style="background-color:rgb(245,245,245);color:rgb(0,34,0);font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;font-size:13px;white-space:pre-wrap">17.0582</span><span style="background-color:rgb(245,245,245);color:rgb(0,34,0);font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;font-size:13px;white-space:pre-wrap"> (String)</span></div>
</div>
</div>
<div>OvmsMetrics.Value("xiq.v.trip.consumption",
"mipkwh",
true) -> <span style="background-color:rgb(245,245,245);color:rgb(0,34,0);font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;font-size:13px;white-space:pre-wrap">3.64264</span><span style="background-color:rgb(245,245,245);color:rgb(0,34,0);font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;font-size:13px;white-space:pre-wrap"> (Number)</span><br>
</div>
<div>OvmsMetrics.Value("xiq.v.trip.consumption",
"mipkwh",
false) -> <span style="background-color:rgb(245,245,245);color:rgb(0,34,0);font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;font-size:13px;white-space:pre-wrap">3.64264Mi/kWh</span><span style="background-color:rgb(245,245,245);color:rgb(0,34,0);font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;font-size:13px;white-space:pre-wrap"> (String)</span><br>
</div>
<div> OvmsMetrics.Value("xiq.v.trip.consumption",
"native",
false) -> <span style="font-size:13px;background-color:rgb(245,245,245);color:rgb(0,34,0);font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;white-space:pre-wrap">17.0582km/kWh</span><span style="font-size:13px;background-color:rgb(245,245,245);color:rgb(0,34,0);font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;white-space:pre-wrap"> (String)</span> </div>
<div><br>
</div>
<div>and</div>
<div>
<div>OvmsMetrics.Value("xiq.v.trip.consumption",
"imperial",
false) -> <span style="background-color:rgb(245,245,245);color:rgb(0,34,0);font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;font-size:13px;white-space:pre-wrap">3.64264Mi/kWh</span><span style="background-color:rgb(245,245,245);color:rgb(0,34,0);font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;font-size:13px;white-space:pre-wrap"> (String)</span><br>
</div>
</div>
<div><br>
</div>
<div>I have
already
implemented
the special
values
'native'
(existing),
'imperial' and
'metric'. </div>
<div><br>
</div>
<div>I was
also thinking
that in the
future you
could have
'user'. Where
for each group
of values:</div>
<div>'temperature',
'distance',
'shortdistance',
'power' etc..
you could have
a user
preference. I
probably won't
implement it
now,.but it
could be cool
that any UI
could just ask
for the user
defined units
(rather than
having a
separate
choice).</div>
<div><br>
</div>
<div><br>
</div>
<div><br>
</div>
<div>//.ichael</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Tue, 8 Nov 2022 at 21:57, Mark Webb-Johnson <<a href="mailto:mark@webb-johnson.net" rel="noreferrer" target="_blank">mark@webb-johnson.net</a>> wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div>
<div dir="ltr" style="color:rgb(0,0,0)">Or perhaps something more specific?</div>
<div dir="ltr" style="color:rgb(0,0,0)"><br>
</div>
<div dir="ltr" style="color:rgb(0,0,0)"> HasValue()</div>
<div dir="ltr" style="color:rgb(0,0,0)"><br>
</div>
<div dir="ltr" style="color:rgb(0,0,0)">Mark</div>
<div><br>
<blockquote type="cite">
<div>On 8 Nov
2022, at 9:01
PM, Michael
Balzer <<a href="mailto:dexter@expeedo.de" rel="noreferrer" target="_blank">dexter@expeedo.de</a>> wrote:</div>
<br>
<div>
<div>
<div>
<div>Signed
PGP part</div>
<div>
<div> That's
basically a
good approach,
but be aware
'IsDefined()'
has an
ambiguous
meaning here,
as with the
API stem
"OvmsMetrics"
it would
naturally be
expected to
mean "is this
metric
defined", not
"does this
metric have a
defined
value".<br>
<br>
An undefined
metric
currently can
be derived
from
'Values()'
returning
undefined, but
that's more an
undocumented
side effect
than intended.<br>
<br>
Maybe
'GetDefined()'
could be a
better name,
leveraging
this
behaviour,
i.e. returning
'undefined'
for an
actually
undefined
metric, and
'null' for a
defined metric
without a
value.<br>
<br>
Regards,<br>
Michael<br>
<br>
<br>
<div>Am
08.11.22 um
13:46 schrieb
Michael
Geddes:<br>
</div>
<blockquote type="cite">
<div dir="ltr">
<div>Ah yes.
Arrays - will
check those.
Yeah, how
about we add a
'IsDefined'
method to
metrics
instead of the
null thing (it
does sound
like it will
upset too many
applecarts).</div>
<div><br>
</div>
<div>//.</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Tue, 8 Nov 2022 at 20:35, Michael Balzer <<a href="mailto:dexter@expeedo.de" rel="noreferrer" target="_blank">dexter@expeedo.de</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div> Michael,<br>
<br>
looks all good
to me, once
again nice
find with the
decode
argument.
Adding decode
to the Value()
call was only
for symmetry
IIRC, the main
use was with
GetValues() (<a href="https://docs.openvehicles.com/en/latest/userguide/scripting.html#ovmsmetrics" rel="noreferrer" target="_blank">https://docs.openvehicles.com/en/latest/userguide/scripting.html#ovmsmetrics</a>).<br>
<br>
Don't forget
to test
arrays, e.g.
"v.t.pressure"
&
"v.t.temp".<br>
<br>
Returning null
for an
undefined
metric seems
like a natural
choice, but is
a rather deep
change, as for
consistency
not only the
Duktape
metrics API
but also the
Web UI metrics
API would need
to be changed
accordingly.
Unless you've
got a real use
case that
needs that, we
should be
careful.<br>
<br>
Regards,<br>
Michael<br>
<br>
<br>
<div>Am
07.11.22 um
15:00 schrieb
Michael
Geddes:<br>
</div>
<blockquote type="cite">
<div dir="ltr">
<div dir="ltr">I
have figured
out a bunch of
stuff and have
implemented
the following:
(having done
away with
needing
AsFloatUnit)
<div><br>
</div>
<div>OvmsMetrics.Value(
{metric} [,
{decode}])</div>
<div>OvmsMetrics.Value(
{metric},
{unit}
[,{decode}])</div>
<div><br>
</div>
<div>It turns
out that the
[decode] flag
wasn't working
anyway (since
the function
was being
registered as
only having 1
param)...</div>
<div>This way
it is still
really 1
function.. but
I check it the
second
parameter is a
'boolean', and
if not.. try
the second
form. </div>
<div><br>
</div>
<div>OvmsMetrics.AsFloat(
{metric}
[,{unit}] )</div>
<div><br>
</div>
<div>and add
the function</div>
<div><br>
</div>
<div>Ovms.Metrics.ValueUnit(
{metric}
[,{unit}]) </div>
<div>This
prints the
value and the
unit.</div>
<div><br>
</div>
<div>Here's a
sample
function and
the output!
This also
shows the
types of the
output.</div>
<div><br>
</div>
<div><font face="monospace">(function()
{<br>
x =
OvmsMetrics.Value("xiq.v.trip.consumption");<br>
print(
(typeof x) +
": "+ x+"\n"
);<br>
x =
OvmsMetrics.Value("xiq.v.trip.consumption",
false);<br>
print(
(typeof x) +
": "+ x +"\n"
);<br>
x =
OvmsMetrics.Value("xiq.v.trip.consumption","kmpkwh")<br>
print(
(typeof x) +
": "+ x
+"\n");<br>
x =
OvmsMetrics.Value("xiq.v.trip.consumption",
"mipkwh",
false) <br>
print(
(typeof x) +
": "+ x
+"\n");<br>
x =
OvmsMetrics.ValueUnit("xiq.v.trip.consumption")<br>
print(
(typeof x) +
": "+ x
+"\n");<br>
x =
OvmsMetrics.ValueUnit("xiq.v.trip.consumption","mipkwh")<br>
print(
(typeof x) +
": "+ x
+"\n");<br>
x =
OvmsMetrics.AsFloat("xiq.v.trip.consumption")<br>
print(
(typeof x) +
": "+ x
+"\n");<br>
x =
OvmsMetrics.AsFloat("xiq.v.trip.consumption","kmpkwh")<br>
print(
(typeof x) +
": "+ x
+"\n");<br>
})();</font><br>
</div>
<div><br>
</div>
<div>
<pre id="m_4886991932006770610m_1082575795986022020m_-6437764485757861817m_1446710767644746708m_3389478097269637711m_-3595551468962657953m_-358274377416053507m_-7644593744426345619m_-5441616086226233372m_8405494616978842232m_-5904723395924573806m_1733173679174480992m_-138117451584655546m_5484224439251412587m_-6783916119872647666m_7514939671383041717m_-2249740601380801512gmail-output" style="box-sizing:border-box;overflow:auto;font-family:ui-monospace,"Cascadia Mono","Segoe UI Mono",Hack,"Source Code Pro","Roboto Mono",Menlo,Monaco,Consolas,monospace;font-size:13px;padding:9.5px;margin-top:0px;margin-bottom:10px;line-height:1.42857;color:rgb(0,34,0);word-break:break-all;background-color:rgb(245,245,245);border:1px solid rgb(204,204,204);border-radius:4px;height:165px;white-space:pre-wrap">number: 17.0582
string: 17.0582
number: 5.86227
string: 3.64264
string: 17.0582kWh/100km
string: 3.64264mi/kWh
number: 17.0582
number: 5.86227</pre>
</div>
<div><br>
</div>
<div><br>
</div>
<div>It still
might be an
idea to use
'null' as a
return value
if the metrics
is<font face="monospace">
!IsDefined() </font><font face="arial,
sans-serif">but
that would be
changing the
existing
behaviour
slightly.</font></div>
<div><font face="arial,
sans-serif"><br>
</font></div>
<div><font face="arial,
sans-serif">//.ichael</font></div>
<div><br>
</div>
</div>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Mon, 7 Nov 2022 at 08:12, Michael Geddes <<a href="mailto:frog@bunyip.wheelycreek.net" rel="noreferrer" target="_blank">frog@bunyip.wheelycreek.net</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div dir="ltr">I've
worked out
what the
decode flag is
for and how it
works, and I
think how
optional
params work. <br>
<div>I'm
pretty sure I
won't need
the
'AsFloatUnit'
function; the
unit would be
an option to
AsFloat();
I'll know that
soon.</div>
<div><br>
</div>
<div>The
'Value'
function is
more
complicated
because of the
optional
decode bool. I
guess I could
add the Unit
to the end of
that.</div>
<div><br>
</div>
<div>ValueUnit
could be still
useful then to
provide a
'Value +
Unit'.</div>
<div><br>
</div>
<div>Question:
Is there a
reason we
shouldn't be
returning
with <span style="color:rgb(220,220,170);background-color:rgb(30,30,30);font-family:Consolas,"Courier New",monospace;font-size:14px;white-space:pre-wrap">duk_push_null</span>
if the
metric
!IsDefined()
in both
AsFloat() and
Value(metric,true) cases?</div>
<div><br>
</div>
<div>//.ichael</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Sun, 6 Nov 2022 at 11:22, Michael Geddes <<a href="mailto:frog@bunyip.wheelycreek.net" rel="noreferrer" target="_blank">frog@bunyip.wheelycreek.net</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div dir="ltr">
<div>Right, so
I've
implemented
some stuff
that seems to
work quite
well. <br>
</div>
<div><br>
</div>
<div><a href="https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/pull/764" rel="noreferrer" target="_blank">https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/pull/764</a>
should be
ready now
after a couple
of stupid
mistakes
slipped
through.
This
absolutely
needs somebody
to review it
please!
(There's a
reason why
I've converted
some if()'s to
switch() -
which is that
it will be
used in the
follow-up
commit).</div>
<div><br>
</div>
<div>The
commit that
will follow on
from that it
implements the
new Units:
kWh/100km,
km/kWh and
mi/kWh.</div>
<div><br>
</div>
<div>This is a
summary of
what I've
implemented
for scripting
- including
showing the
unit codes I
have so far.
I've
considered a
few things:</div>
<div> *
Should some of
the longer
unit codes be
shortened (eg
mi, mins, m,
ft, deg, perc)</div>
<div> * The
unit codes
could be much
more re<font face="arial,
sans-serif">gular
and separated
by dots eg: </font></div>
<div><font face="arial,
sans-serif">
watthours
-> w.h</font></div>
<div><font face="arial,
sans-serif">
kwhp100km
->
kw.h_100km or
kw.h/100km</font></div>
<div><font face="arial,
sans-serif">
miph
-> mi_h or
mi/h (or
should it be
mph).</font></div>
<div><font face="arial,
sans-serif">
psi
-> <a href="http://p_in.in/" rel="noreferrer" target="_blank">p_in.in</a> or
p/<a href="http://in.in/" rel="noreferrer" target="_blank">in.in</a> or <a href="http://lb_in.in/" rel="noreferrer" target="_blank">lb_in.in</a>
(yes, slightly
weird, but
predictable)</font></div>
<div><font face="arial,
sans-serif"> </font><br>
</div>
<b style="font-family:monospace">OVMS#
metric units</b><br>
<font face="monospace">
km :
km</font><br>
<font face="monospace">
miles : M</font><br>
<font face="monospace">
meters : m</font><br>
<font face="monospace">
feet :
ft</font><br>
<font face="monospace">
celcius :
°C</font><br>
<font face="monospace">
fahrenheit :
°F</font><br>
<font face="monospace">
kpa :
kPa</font><br>
<font face="monospace">
pa :
Pa</font><br>
<font face="monospace">
psi :
psi</font><br>
<font face="monospace">
volts : V</font><br>
<font face="monospace">
amps : A</font><br>
<font face="monospace">
</font>amphours<font face="monospace"> : Ah</font><br>
<font face="monospace">
kw :
kW</font><br>
<font face="monospace">
kwh :
kWh</font><br>
<font face="monospace">
watts : W</font><br>
<font face="monospace">
</font>watthours<font face="monospace"> : Wh</font><br>
<font face="monospace">
seconds :
Sec</font><br>
<font face="monospace">
minutes :
Min </font><br>
<font face="monospace">
hours :
Hour</font><br>
<font face="monospace">
utc :
UTC</font><br>
<font face="monospace">
degrees : °</font><br>
<font face="monospace">
kmph :
km/h</font><br>
<font face="monospace">
</font>miph<font face="monospace"> : Mph</font><br>
<font face="monospace">
</font>kmphps<font face="monospace"> : km/h/s</font><br>
<font face="monospace">
</font>miphps<font face="monospace"> : Mph/s</font><br>
<font face="monospace">
mpss :
m/s²</font><br>
<font face="monospace">
dbm :
dBm</font><br>
<font face="monospace">
sq :
sq</font><br>
<font face="monospace">
percent : %</font><br>
<font face="monospace">
whpkm :
Wh/km</font><br>
<font face="monospace">
</font>whpmi<font face="monospace"> : Wh/mi</font><br>
<font face="monospace">
kwhp100km :
kWh/100km</font><br>
<font face="monospace">
</font>kmpkwh<font face="monospace"> : km/kWh</font><br>
<font face="monospace">
</font>mipkwh<font face="monospace"> : mi/kWh</font><br>
<font face="monospace">
nm :
Nm</font><br>
<font face="monospace"><br>
<b>OVMS#
metric unit mi</b><br>
miles :
M<br>
</font></div>
</blockquote>
</div>
</blockquote>
</div>
</div>
</blockquote>
</div>
</blockquote>
</div>
</div>
</blockquote>
</div>
</div>
</div>
</div>
</div>
</blockquote>
</div>
</div>
</blockquote>
</div>
</blockquote>
</div>
</blockquote>
</div>
</blockquote>
</div>
</div>
</blockquote>
</div>
</blockquote>
</div>
</blockquote>
</div>
</div>
</div>
</div>
</blockquote>
</div>
</blockquote>
</div>
</div>
</blockquote>
</div>
</div>
</blockquote>
</div>
</blockquote>
</div>
</div>
</div>
</div>
</blockquote>
</div>
<br>
<fieldset></fieldset>
<pre>_______________________________________________
OvmsDev mailing list
<a href="mailto:OvmsDev@lists.openvehicles.com" target="_blank">OvmsDev@lists.openvehicles.com</a>
<a href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev" target="_blank">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a>
</pre>
</blockquote>
<br>
<pre cols="72">--
Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal
Fon 02333 / 833 5735 * Handy 0176 / 206 989 26</pre>
</div>
_______________________________________________<br>
OvmsDev mailing list<br>
<a href="mailto:OvmsDev@lists.openvehicles.com" target="_blank">OvmsDev@lists.openvehicles.com</a><br>
<a href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev" rel="noreferrer" target="_blank">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a><br>
</blockquote>
</div>
</div>
<br>
<fieldset></fieldset>
<pre>_______________________________________________
OvmsDev mailing list
<a href="mailto:OvmsDev@lists.openvehicles.com" target="_blank">OvmsDev@lists.openvehicles.com</a>
<a href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev" target="_blank">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a>
</pre>
</blockquote>
<br>
<pre cols="72">--
Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal
Fon 02333 / 833 5735 * Handy 0176 / 206 989 26</pre>
</div>
_______________________________________________<br>
OvmsDev mailing list<br>
<a href="mailto:OvmsDev@lists.openvehicles.com" target="_blank">OvmsDev@lists.openvehicles.com</a><br>
<a href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev" rel="noreferrer" target="_blank">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a><br>
</blockquote>
</div>
</div>
<br>
<fieldset></fieldset>
<pre>_______________________________________________
OvmsDev mailing list
<a href="mailto:OvmsDev@lists.openvehicles.com" target="_blank">OvmsDev@lists.openvehicles.com</a>
<a href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev" target="_blank">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a>
</pre>
</blockquote>
<br>
<pre cols="72">--
Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal
Fon 02333 / 833 5735 * Handy 0176 / 206 989 26</pre>
</div>
_______________________________________________<br>
OvmsDev mailing list<br>
<a href="mailto:OvmsDev@lists.openvehicles.com" target="_blank">OvmsDev@lists.openvehicles.com</a><br>
<a href="http://lists.openvehicles.com/mailman/listinfo/ovmsdev" rel="noreferrer" target="_blank">http://lists.openvehicles.com/mailman/listinfo/ovmsdev</a><br>
</blockquote></div></div>