[Ovmsdev] New Metric Units

Michael Geddes frog at bunyip.wheelycreek.net
Sat Nov 12 17:35:51 HKT 2022


https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/pull/771

I'm hoping this P/R is ok in this form (made of 5 separate commits).

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.

The 'power consumption' is one where it's not just a check-box.. there're 5
possible choice!

I should also add 'bar' for pressure given that for some reason that's
still a thing people want.

//.ichael

On Sat, 12 Nov 2022 at 16:24, Michael Balzer <dexter at expeedo.de> wrote:

> I think this is pretty decent & complete now.
>
> 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.
>
> Regards,
> Michael
>
>
> Am 11.11.22 um 09:54 schrieb Michael Geddes:
>
> Ok - so here's what I have implemented for Duktape and Metrics. (I added
> IsDefined() as well).
> Any thoughts on this?
>
> Noting
>    OvmsMetrics.Float( {metric} ) -> Outputs metric as float (same)
>    OvmsMetrics.Float( {metric}, {unit}) -> Outputs metric as float
> converted to given unit  (new)
>    OvmsMetrics.Value( {metric} )   -> Outputs Metric in native value (same)
>    OvmsMetrics.Value( {metric} , false)   -> Outputs Metric as string and
> no units (same)
>    OvmsMetrics.Value( {metric} ,  {unit})  -> Outputs Metric converted to
> given unit as native value. (new)
>   OvmsMetrics.Value( {metric} ,  {unit}, false )  -> Outputs Metric
> converted to given unit as string including any unit specifier. (new)
> also  OvmsMetric.GetValues( {metric} [,{unit}] [, {converted} ] )  Adds
> similar behaviour to Value() above.
> also the special units '*imperial*' and '*metric*' will convert to the
> associated imperial / metric version of the units as appropriate.
>
> (function() {
>    dump = function (metric) { print( metric+ " ["+(typeof metric)+"]\n"
>  ); }
>    dump_obj = function (obj )  {
>      print('--- Object ----\n')
>      for (var k in obj) {
>        xk = obj[k];
>        print( k+':'+ xk + ' ['+typeof xk+ "]\n");
>      }
>    }
>    dump(OvmsMetrics.Value("xiq.v.trip.consumption"));
>    dump(OvmsMetrics.Value("xiq.v.trip.consumption", false));
>    dump(OvmsMetrics.Value("xiq.v.trip.consumption","kmpkwh"));
>    dump(OvmsMetrics.Value("xiq.v.trip.consumption", "mipkwh", false));
>    dump(OvmsMetrics.AsFloat("xiq.v.trip.consumption"));
>    dump(OvmsMetrics.AsFloat("xiq.v.trip.consumption","kmpkwh"));
>    dump(OvmsMetrics.Value("xiq.v.trip.consumption","imperial"))
>    dump(OvmsMetrics.Value("xiq.v.trip.consumption","imperial", false))
>    dump_obj(OvmsMetrics.GetValues("trip", "metric"))
>    dump_obj(OvmsMetrics.GetValues("trip", "imperial", false))
> })();
>
> With this output:
>
> 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]
>
>
> On Wed, 9 Nov 2022 at 05:47, Michael Geddes <frog at bunyip.wheelycreek.net>
> wrote:
>
>> Yeah - I like HasValue.  I implemented IsDefined() but I will rename it..
>> that's a much clearer name.
>>
>> Another thought. How about if we did this (but also with GetValues() as
>> well - see the special values below)
>>
>> OvmsMetrics.Value("xiq.v.trip.consumption",  true)  -> 17.0582  (Number)
>> OvmsMetrics.Value("xiq.v.trip.consumption",  false)  -> 17.0582  (String)
>> OvmsMetrics.Value("xiq.v.trip.consumption", "mipkwh", true)  -> 3.64264
>> (Number)
>> OvmsMetrics.Value("xiq.v.trip.consumption", "mipkwh", false)  ->
>> 3.64264Mi/kWh  (String)
>>  OvmsMetrics.Value("xiq.v.trip.consumption", "native", false)  ->
>> 17.0582km/kWh  (String)
>>
>> and
>> OvmsMetrics.Value("xiq.v.trip.consumption", "imperial", false)  ->
>> 3.64264Mi/kWh  (String)
>>
>> I have already implemented the special values 'native' (existing),
>> 'imperial' and 'metric'.
>>
>> I was also thinking that in the future you could have 'user'. Where for
>> each group of values:
>> '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).
>>
>>
>>
>> //.ichael
>>
>> On Tue, 8 Nov 2022 at 21:57, Mark Webb-Johnson <mark at webb-johnson.net>
>> wrote:
>>
>>> Or perhaps something more specific?
>>>
>>>     HasValue()
>>>
>>> Mark
>>>
>>> On 8 Nov 2022, at 9:01 PM, Michael Balzer <dexter at expeedo.de> wrote:
>>>
>>> Signed PGP part
>>> 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".
>>>
>>> An undefined metric currently can be derived from 'Values()' returning
>>> undefined, but that's more an undocumented side effect than intended.
>>>
>>> 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.
>>>
>>> Regards,
>>> Michael
>>>
>>>
>>> Am 08.11.22 um 13:46 schrieb Michael Geddes:
>>>
>>> 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).
>>>
>>> //.
>>>
>>> On Tue, 8 Nov 2022 at 20:35, Michael Balzer <dexter at expeedo.de> wrote:
>>>
>>>> Michael,
>>>>
>>>> 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() (
>>>> https://docs.openvehicles.com/en/latest/userguide/scripting.html#ovmsmetrics
>>>> ).
>>>>
>>>> Don't forget to test arrays, e.g. "v.t.pressure" & "v.t.temp".
>>>>
>>>> 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.
>>>>
>>>> Regards,
>>>> Michael
>>>>
>>>>
>>>> Am 07.11.22 um 15:00 schrieb Michael Geddes:
>>>>
>>>> I have figured out a bunch of stuff and have implemented the following:
>>>> (having done away with needing AsFloatUnit)
>>>>
>>>> OvmsMetrics.Value( {metric} [, {decode}])
>>>> OvmsMetrics.Value( {metric}, {unit} [,{decode}])
>>>>
>>>> It turns out that the [decode] flag wasn't working anyway (since the
>>>> function was being registered as only having 1 param)...
>>>> 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.
>>>>
>>>> OvmsMetrics.AsFloat( {metric} [,{unit}] )
>>>>
>>>> and add the function
>>>>
>>>> Ovms.Metrics.ValueUnit( {metric} [,{unit}])
>>>> This prints the value and the unit.
>>>>
>>>> Here's a sample function and the output! This also shows the types of
>>>> the output.
>>>>
>>>> (function() {
>>>>    x = OvmsMetrics.Value("xiq.v.trip.consumption");
>>>>    print( (typeof x) + ": "+  x+"\n"  );
>>>>    x = OvmsMetrics.Value("xiq.v.trip.consumption", false);
>>>>    print( (typeof x) + ": "+  x +"\n" );
>>>>    x =  OvmsMetrics.Value("xiq.v.trip.consumption","kmpkwh")
>>>>    print( (typeof x) + ": "+ x +"\n");
>>>>    x =  OvmsMetrics.Value("xiq.v.trip.consumption", "mipkwh", false)
>>>>    print( (typeof x) + ": "+ x +"\n");
>>>>    x =  OvmsMetrics.ValueUnit("xiq.v.trip.consumption")
>>>>    print( (typeof x) + ": "+ x +"\n");
>>>>    x =  OvmsMetrics.ValueUnit("xiq.v.trip.consumption","mipkwh")
>>>>    print( (typeof x) + ": "+ x +"\n");
>>>>    x =  OvmsMetrics.AsFloat("xiq.v.trip.consumption")
>>>>    print( (typeof x) + ": "+ x +"\n");
>>>>    x =  OvmsMetrics.AsFloat("xiq.v.trip.consumption","kmpkwh")
>>>>    print( (typeof x) + ": "+ x +"\n");
>>>> })();
>>>>
>>>> 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
>>>>
>>>>
>>>>
>>>> It still might be an idea to use 'null' as a return value if the
>>>> metrics is !IsDefined() but that would be changing the existing
>>>> behaviour slightly.
>>>>
>>>> //.ichael
>>>>
>>>> On Mon, 7 Nov 2022 at 08:12, Michael Geddes <
>>>> frog at bunyip.wheelycreek.net> wrote:
>>>>
>>>>> I've worked out what the decode flag is for and how it works, and I
>>>>> think how optional params work.
>>>>> I'm pretty sure I won't  need the 'AsFloatUnit' function; the unit
>>>>> would be an option to AsFloat(); I'll know that soon.
>>>>>
>>>>> The 'Value' function is more complicated because of the optional
>>>>> decode bool. I guess I could add the Unit to the end of that.
>>>>>
>>>>> ValueUnit could be still useful then to provide a 'Value + Unit'.
>>>>>
>>>>> Question:  Is there a reason we shouldn't be returning with
>>>>> duk_push_null    if the metric !IsDefined()  in both AsFloat() and
>>>>> Value(metric,true) cases?
>>>>>
>>>>> //.ichael
>>>>>
>>>>> On Sun, 6 Nov 2022 at 11:22, Michael Geddes <
>>>>> frog at bunyip.wheelycreek.net> wrote:
>>>>>
>>>>>> Right, so I've implemented some stuff that seems to work quite well.
>>>>>>
>>>>>>
>>>>>> https://github.com/openvehicles/Open-Vehicle-Monitoring-System-3/pull/764
>>>>>> 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).
>>>>>>
>>>>>> The commit that will follow on from that it implements the new Units:
>>>>>> kWh/100km, km/kWh  and  mi/kWh.
>>>>>>
>>>>>> 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:
>>>>>>   * Should some of the longer unit codes be shortened  (eg mi, mins,
>>>>>> m, ft, deg, perc)
>>>>>>   * The unit codes could be much more regular and separated by dots
>>>>>> eg:
>>>>>>         watthours -> w.h
>>>>>>         kwhp100km -> kw.h_100km or kw.h/100km
>>>>>>         miph ->  mi_h or mi/h  (or should it be mph).
>>>>>>         psi -> p_in.in or p/in.in or lb_in.in (yes, slightly weird,
>>>>>> but predictable)
>>>>>>
>>>>>> *OVMS# metric units*
>>>>>>           km : km
>>>>>>        miles : M
>>>>>>       meters : m
>>>>>>         feet : ft
>>>>>>      celcius : °C
>>>>>>   fahrenheit : °F
>>>>>>          kpa : kPa
>>>>>>           pa : Pa
>>>>>>          psi : psi
>>>>>>        volts : V
>>>>>>         amps : A
>>>>>>     amphours : Ah
>>>>>>           kw : kW
>>>>>>          kwh : kWh
>>>>>>        watts : W
>>>>>>    watthours : Wh
>>>>>>      seconds : Sec
>>>>>>      minutes : Min
>>>>>>        hours : Hour
>>>>>>          utc : UTC
>>>>>>      degrees : °
>>>>>>         kmph : km/h
>>>>>>         miph : Mph
>>>>>>       kmphps : km/h/s
>>>>>>       miphps : Mph/s
>>>>>>         mpss : m/s²
>>>>>>          dbm : dBm
>>>>>>           sq : sq
>>>>>>      percent : %
>>>>>>        whpkm : Wh/km
>>>>>>        whpmi : Wh/mi
>>>>>>    kwhp100km : kWh/100km
>>>>>>       kmpkwh : km/kWh
>>>>>>       mipkwh : mi/kWh
>>>>>>           nm : Nm
>>>>>>
>>>>>> *OVMS# metric unit mi*
>>>>>>        miles : M
>>>>>>      minutes : Min
>>>>>>         miph : Mph
>>>>>>       miphps : Mph/s
>>>>>>        whpmi : Wh/mi
>>>>>>       mipkwh : mi/kWh
>>>>>>
>>>>>>
>>>>>> *OVMS# metric get xiq.v.trip.consumption *17.0597kWh/100km
>>>>>>
>>>>>> *OVMS# metric get xiq.v.trip.consumption kpkwh *5.86177km/kWh
>>>>>>
>>>>>> *OVMS# metric get xiq.v.trip.consumption mpkwh *3.64233mi/kWh
>>>>>>
>>>>>>
>>>>>> *OVMS# metric set xiq.c.speed 5 miph *Metric set
>>>>>>
>>>>>> *OVMS# metric get xiq.c.speed *8.04673km/h
>>>>>>
>>>>>> *OVMS# metric get xiq.c.speed miph *5Mph
>>>>>>
>>>>>> And then in DukTape - there are some questions I have about the
>>>>>> implementation:
>>>>>> * Names of functions? Better ideas?
>>>>>> * Should ValueUnit output the units?
>>>>>> * In Value() there is the line    bool decode = duk_opt_boolean(ctx,
>>>>>> 1, true);
>>>>>>     * What does 'decode' mean here?
>>>>>>     * Do I need it for ValueUnit() ?
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> * (function() {    print(
>>>>>> OvmsMetrics.Value("xiq.v.trip.consumption"));    print("\n")    print(
>>>>>> OvmsMetrics.ValueUnit("xiq.v.trip.consumption",""));    print("\n")
>>>>>>  print( OvmsMetrics.ValueUnit("xiq.v.trip.consumption","mipkwh"));
>>>>>>  print("\n")    print(
>>>>>> OvmsMetrics.AsFloatUnit("xiq.v.trip.consumption","kmpkwh")); })();*
>>>>>> --- Output ---
>>>>>> 17.0597
>>>>>> 17.0597kWh/100km
>>>>>> 3.64233mi/kWh
>>>>>> 5.86177
>>>>>> ------
>>>>>>
>>>>>> The basic stuff all works - it's just quibbling over the details..
>>>>>> but let's get them right!
>>>>>>
>>>>>> //.ichael
>>>>>>
>>>>>> On Sat, 5 Nov 2022 at 20:09, Michael Geddes <
>>>>>> frog at bunyip.wheelycreek.net> wrote:
>>>>>>
>>>>>>> Yeah - this was copied code from kia/kona and is what triggered
>>>>>>> these ideas; I totally agree this shouldn't be doubled up on.
>>>>>>>
>>>>>>> I've got some commits centred round Metrics that I'll just check
>>>>>>> over and push up ... and then I'll just have the single xiq.v.
>>>>>>> trip.consumption metric (unless you have some ideas for the
>>>>>>> namespace) which will be much neater.
>>>>>>>
>>>>>>> If it's ok with you then I might do that unit conversion proposal.
>>>>>>> Would it ok if the unit specifications were the same as to the
>>>>>>> programatic codes in ovms_metrics.h?
>>>>>>> (kWh,   WattHours , MetersPSS )
>>>>>>> I would probably add a command
>>>>>>> metric units <spec>
>>>>>>> to list all (matching) units and their associated Labels.
>>>>>>>
>>>>>>> //.ichael
>>>>>>>
>>>>>>> On Sat, 5 Nov 2022 at 18:48, Michael Balzer <dexter at expeedo.de>
>>>>>>> wrote:
>>>>>>>
>>>>>>>> Michael,
>>>>>>>>
>>>>>>>> adding unit conversion support to the shell and Duktape commands is
>>>>>>>> a good idea.
>>>>>>>>
>>>>>>>> Metrics are not meant to provide a user interface, they should be
>>>>>>>> defined to be efficient and non-redundant.
>>>>>>>>
>>>>>>>> Btw, metrics names also shall not use upper case characters, and
>>>>>>>> shall only use "." as a separator.
>>>>>>>>
>>>>>>>> Regards,
>>>>>>>> Michael
>>>>>>>>
>>>>>>>>
>>>>>>>> Am 05.11.22 um 11:22 schrieb Michael Geddes:
>>>>>>>>
>>>>>>>> Hi all,
>>>>>>>> Some of the code I copied from Kona/Kia code had both kwh/100km and
>>>>>>>> km/kwh metrics in the code as 'Other'.
>>>>>>>> Adding the various power consumption Units is not particularly hard
>>>>>>>> (I will have a pull-request soon) - though the conversions between them all
>>>>>>>> required some thought!
>>>>>>>> ... but it also made me think these two metrics that are (with the
>>>>>>>> consumption units added) defined like this:
>>>>>>>> m_v_trip_consumption1 =
>>>>>>>> MyMetrics.InitFloat("xiq.v.trip.consumption.KWh/100km", 10, 0, kWHP100K);
>>>>>>>> m_v_trip_consumption2 = MyMetrics.InitFloat("
>>>>>>>> xiq.v.trip.consumption.km/kWh", 10, 0, kPkWH);
>>>>>>>>
>>>>>>>> These are effectively the same metric but in different units!
>>>>>>>> I'm wondering if we would be better to have scripting and Duktape
>>>>>>>> support for converting metrics to different unit!  This might be also quite
>>>>>>>> useful for those strange countries that insist on using miles as a
>>>>>>>> measurement.
>>>>>>>>
>>>>>>>> On top of the 'metric list' and 'metric set' we could add a 'metric
>>>>>>>> get' which gets a single value.. and add unit support for get/set.
>>>>>>>>
>>>>>>>> I've also got a pull request that improves the precision of the
>>>>>>>> km<->mi conversions and factors it out.
>>>>>>>>
>>>>>>>> //.ichael
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> OvmsDev mailing listOvmsDev at lists.openvehicles.comhttp://lists.openvehicles.com/mailman/listinfo/ovmsdev
>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal
>>>>>>>> Fon 02333 / 833 5735 * Handy 0176 / 206 989 26
>>>>>>>>
>>>>>>>> _______________________________________________
>>>>>>>> OvmsDev mailing list
>>>>>>>> OvmsDev at lists.openvehicles.com
>>>>>>>> http://lists.openvehicles.com/mailman/listinfo/ovmsdev
>>>>>>>>
>>>>>>>
>>>> _______________________________________________
>>>> OvmsDev mailing listOvmsDev at lists.openvehicles.comhttp://lists.openvehicles.com/mailman/listinfo/ovmsdev
>>>>
>>>>
>>>> --
>>>> Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal
>>>> Fon 02333 / 833 5735 * Handy 0176 / 206 989 26
>>>>
>>>> _______________________________________________
>>>> OvmsDev mailing list
>>>> OvmsDev at lists.openvehicles.com
>>>> http://lists.openvehicles.com/mailman/listinfo/ovmsdev
>>>>
>>>
>>> _______________________________________________
>>> OvmsDev mailing listOvmsDev at lists.openvehicles.comhttp://lists.openvehicles.com/mailman/listinfo/ovmsdev
>>>
>>>
>>> --
>>> Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal
>>> Fon 02333 / 833 5735 * Handy 0176 / 206 989 26
>>>
>>>
>>>
>>> _______________________________________________
>>> OvmsDev mailing list
>>> OvmsDev at lists.openvehicles.com
>>> http://lists.openvehicles.com/mailman/listinfo/ovmsdev
>>>
>>
> _______________________________________________
> OvmsDev mailing listOvmsDev at lists.openvehicles.comhttp://lists.openvehicles.com/mailman/listinfo/ovmsdev
>
>
> --
> Michael Balzer * Helkenberger Weg 9 * D-58256 Ennepetal
> Fon 02333 / 833 5735 * Handy 0176 / 206 989 26
>
> _______________________________________________
> OvmsDev mailing list
> OvmsDev at lists.openvehicles.com
> http://lists.openvehicles.com/mailman/listinfo/ovmsdev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openvehicles.com/pipermail/ovmsdev/attachments/20221112/693eae92/attachment-0001.htm>


More information about the OvmsDev mailing list