Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HyundaiBlueLinkAPIUSA Vehicle.daily_stats NOT consistent with the other region implementations #617

Closed
ZuinigeRijder opened this issue Aug 24, 2024 · 39 comments

Comments

@ZuinigeRijder
Copy link
Collaborator

  • Hyundai / Kia Connect version: 3.22.7
  • Python version: 3.9.13
  • Operating System: Windows

Description

Region Europe was the first one (by me) implementing Vehicle._daily_stats, Vehicle.month_trip_info and Vehicle.day_trip_info.
Later on, also implementations followed for region Australia and China. Also HyundaiBlueLinkAPIUSA has partly implemented Vehicle.daily_stats, however the implementation is NOT consistent with the other region implementations.

The Bluelink API is very different for HyundaiBlueLinkAPIUSA, see also this discussion in hyundai_kia_connect_monitor.

  1. vehicle.daily_stats is not sorted, only sorted in KiaUvoApiEU.py, same problem for other regions.
  2. In USA you have daily stats information for all trips (so no cumulative day value, but for each trip the actual values), in Europe (and the other regions?) only the cumulative latest value per day.
  3. method update_day_trip_info is NOT overruled/implemented in HyundaiBlueLinkAPIUSA.py, although the information seems available for the last day?

What I Did

  1. made a local fix for issue 1, so the sorting is done in setters of Vehicle.daily_stats, Vehicle.month_trip_info and Vehicle.day_trip_info.
  2. checked with hyundai_kia_connect_monitor/debug.py what information is returned for KiaUvoApiEU.py and for HyundaiBlueLinkAPIUSA.py (latter provided by @gyveri )

See next posts for the API for getting daily_stats, month_trip_info, Vehicle.day_trip_info from the debug.py output.

@ZuinigeRijder
Copy link
Collaborator Author

Relevant debug.py output for KiaUvoApiEU.py.

get_driving_info responseAlltime

{
    "periodTarget": 1
}
POST /api/v1/spa/vehicles/<id>/drvhistory

{
    'retCode': 'S',
     'resCode': '0000',
     'resMsg': 
    {
        'drivingInfo': 
        [
            
            {
                'drivingPeriod': 0,
                 'totalPwrCsp': 462790,
                 'motorPwrCsp': 424878,
                 'climatePwrCsp': 5662,
                 'eDPwrCsp': 32250,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 123085,
                 'calculativeOdo': 3489
            },
             
            {
                'drivingPeriod': 1,
                 'totalPwrCsp': 6611,
                 'motorPwrCsp': 6069,
                 'climatePwrCsp': 80,
                 'eDPwrCsp': 460,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 1758,
                 'calculativeOdo': 49.84285714285714
            }
        ],
         'drivingInfoDetail': 
        [
            
            {
                'drivingPeriod': 1,
                 'drivingDate': '202408',
                 'totalPwrCsp': 167204,
                 'motorPwrCsp': 156773,
                 'climatePwrCsp': 1221,
                 'eDPwrCsp': 9210,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 38409,
                 'calculativeOdo': 1259
            },
             
            {
                'drivingPeriod': 1,
                 'drivingDate': '202407',
                 'totalPwrCsp': 136405,
                 'motorPwrCsp': 124091,
                 'climatePwrCsp': 3324,
                 'eDPwrCsp': 8990,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 39281,
                 'calculativeOdo': 1057
            },
             
            {
                'drivingPeriod': 1,
                 'drivingDate': '202406',
                 'totalPwrCsp': 150820,
                 'motorPwrCsp': 137853,
                 'climatePwrCsp': 1117,
                 'eDPwrCsp': 11850,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 41076,
                 'calculativeOdo': 1114
            },
             
            {
                'drivingPeriod': 1,
                 'drivingDate': '202405',
                 'totalPwrCsp': 8361,
                 'motorPwrCsp': 6161,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 2200,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 4319,
                 'calculativeOdo': 59
            }
        ]
    },
     'msgId': '25b64640-6182-11ef-aa3a-80dc536d6bde'
}

get_driving_info response30d for DailyStats

{
    "periodTarget": 0
}
POST /api/v1/spa/vehicles/<id>/drvhistory
 
{
    'retCode': 'S',
     'resCode': '0000',
     'resMsg': 
    {
        'drivingInfo': 
        [
            
            {
                'drivingPeriod': 0,
                 'totalPwrCsp': 229558,
                 'motorPwrCsp': 214853,
                 'climatePwrCsp': 2665,
                 'eDPwrCsp': 12040,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 48608,
                 'calculativeOdo': 1743
            },
             
            {
                'drivingPeriod': 1,
                 'totalPwrCsp': 9980,
                 'motorPwrCsp': 9341,
                 'climatePwrCsp': 115,
                 'eDPwrCsp': 523,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 2113,
                 'calculativeOdo': 75.78260869565217
            },
             
            {
                'drivingPeriod': 2,
                 'totalPwrCsp': 1816,
                 'motorPwrCsp': 1576,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 240,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 1098,
                 'calculativeOdo': 15
            }
        ],
         'drivingInfoDetail': 
        [
            
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240823',
                 'totalPwrCsp': 1816,
                 'motorPwrCsp': 1576,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 240,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 1098,
                 'calculativeOdo': 15
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240822',
                 'totalPwrCsp': 597,
                 'motorPwrCsp': 487,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 110,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 546,
                 'calculativeOdo': 4
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240821',
                 'totalPwrCsp': 2014,
                 'motorPwrCsp': 1794,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 220,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 1365,
                 'calculativeOdo': 17
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240820',
                 'totalPwrCsp': 40600,
                 'motorPwrCsp': 38500,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 2100,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 9484,
                 'calculativeOdo': 278
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240819',
                 'totalPwrCsp': 3233,
                 'motorPwrCsp': 2564,
                 'climatePwrCsp': 239,
                 'eDPwrCsp': 430,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 1940,
                 'calculativeOdo': 27
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240818',
                 'totalPwrCsp': 19984,
                 'motorPwrCsp': 18859,
                 'climatePwrCsp': 345,
                 'eDPwrCsp': 780,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 4756,
                 'calculativeOdo': 157
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240817',
                 'totalPwrCsp': 1743,
                 'motorPwrCsp': 1533,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 210,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 1062,
                 'calculativeOdo': 14
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240816',
                 'totalPwrCsp': 52654,
                 'motorPwrCsp': 50664,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 1990,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 5122,
                 'calculativeOdo': 396
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240815',
                 'totalPwrCsp': 5717,
                 'motorPwrCsp': 4925,
                 'climatePwrCsp': 262,
                 'eDPwrCsp': 530,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 3023,
                 'calculativeOdo': 50
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240813',
                 'totalPwrCsp': 1197,
                 'motorPwrCsp': 1007,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 190,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 733,
                 'calculativeOdo': 11
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240812',
                 'totalPwrCsp': 50,
                 'motorPwrCsp': 10,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 40,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 0,
                 'calculativeOdo': 0
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240811',
                 'totalPwrCsp': 723,
                 'motorPwrCsp': 633,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 90,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 353,
                 'calculativeOdo': 6
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240808',
                 'totalPwrCsp': 11621,
                 'motorPwrCsp': 10416,
                 'climatePwrCsp': 375,
                 'eDPwrCsp': 830,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 2932,
                 'calculativeOdo': 80
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240807',
                 'totalPwrCsp': 1701,
                 'motorPwrCsp': 1541,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 160,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 838,
                 'calculativeOdo': 14
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240806',
                 'totalPwrCsp': 2405,
                 'motorPwrCsp': 2065,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 340,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 1897,
                 'calculativeOdo': 24
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240804',
                 'totalPwrCsp': 19421,
                 'motorPwrCsp': 18701,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 720,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 2349,
                 'calculativeOdo': 154
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240803',
                 'totalPwrCsp': 24,
                 'motorPwrCsp': 4,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 20,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 0,
                 'calculativeOdo': 0
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240801',
                 'totalPwrCsp': 1704,
                 'motorPwrCsp': 1494,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 210,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 911,
                 'calculativeOdo': 12
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240730',
                 'totalPwrCsp': 560,
                 'motorPwrCsp': 470,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 90,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 342,
                 'calculativeOdo': 4
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240729',
                 'totalPwrCsp': 24,
                 'motorPwrCsp': 4,
                 'climatePwrCsp': 0,
                 'eDPwrCsp': 20,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 0,
                 'calculativeOdo': 0
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240728',
                 'totalPwrCsp': 6722,
                 'motorPwrCsp': 6190,
                 'climatePwrCsp': 2,
                 'eDPwrCsp': 530,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 2864,
                 'calculativeOdo': 55
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240727',
                 'totalPwrCsp': 54976,
                 'motorPwrCsp': 51411,
                 'climatePwrCsp': 1425,
                 'eDPwrCsp': 2140,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 6993,
                 'calculativeOdo': 425
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240726',
                 'totalPwrCsp': 72,
                 'motorPwrCsp': 5,
                 'climatePwrCsp': 17,
                 'eDPwrCsp': 50,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 0,
                 'calculativeOdo': 0
            },
             
            {
                'drivingPeriod': 0,
                 'drivingDate': '20240725',
                 'totalPwrCsp': 2141,
                 'motorPwrCsp': 1637,
                 'climatePwrCsp': 194,
                 'eDPwrCsp': 310,
                 'batteryMgPwrCsp': 0,
                 'regenPwr': 1171,
                 'calculativeOdo': 18
            }
        ]
    },
     'msgId': '25d3e060-6182-11ef-aa3a-5482b2141be2'
}

get_trip_info response for MonthTripInfo

{
    "tripPeriodType": 0,
     "setTripMonth": 202408
}
POST /api/v1/spa/vehicles/<id>/tripinfo

{
    'retCode': 'S',
     'resCode': '0000',
     'resMsg': 
    {
        'tripPeriodType': 0,
         'monthTripDayCnt': 18,
         'tripDayList': 
        [
            
            {
                'tripDayInMonth': '20240801',
                 'tripCntDay': 5
            },
             
            {
                'tripDayInMonth': '20240803',
                 'tripCntDay': 1
            },
             
            {
                'tripDayInMonth': '20240804',
                 'tripCntDay': 2
            },
             
            {
                'tripDayInMonth': '20240806',
                 'tripCntDay': 3
            },
             
            {
                'tripDayInMonth': '20240807',
                 'tripCntDay': 2
            },
             
            {
                'tripDayInMonth': '20240808',
                 'tripCntDay': 7
            },
             
            {
                'tripDayInMonth': '20240811',
                 'tripCntDay': 2
            },
             
            {
                'tripDayInMonth': '20240812',
                 'tripCntDay': 2
            },
             
            {
                'tripDayInMonth': '20240813',
                 'tripCntDay': 2
            },
             
            {
                'tripDayInMonth': '20240815',
                 'tripCntDay': 3
            },
             
            {
                'tripDayInMonth': '20240816',
                 'tripCntDay': 2
            },
             
            {
                'tripDayInMonth': '20240817',
                 'tripCntDay': 2
            },
             
            {
                'tripDayInMonth': '20240818',
                 'tripCntDay': 3
            },
             
            {
                'tripDayInMonth': '20240819',
                 'tripCntDay': 6
            },
             
            {
                'tripDayInMonth': '20240820',
                 'tripCntDay': 3
            },
             
            {
                'tripDayInMonth': '20240821',
                 'tripCntDay': 3
            },
             
            {
                'tripDayInMonth': '20240822',
                 'tripCntDay': 2
            },
             
            {
                'tripDayInMonth': '20240823',
                 'tripCntDay': 4
            }
        ],
         'tripDrvTime': 1341,
         'tripIdleTime': 97,
         'tripDist': 1259,
         'tripAvgSpeed': 37.2,
         'tripMaxSpeed': 120
    },
     'msgId': '25f10550-6182-11ef-a66f-0e5586749374'
}

get_trip_info Request for DayTripInfo

{
    'tripPeriodType': 1,
     'setTripDay': '20240823'
}
POST /api/v1/spa/vehicles/9ac0c568-e9fe-4b75-a1c4-0d772063f9fd/tripinfo

{
    'retCode': 'S',
     'resCode': '0000',
     'resMsg': 
    {
        'tripPeriodType': 1,
         'offset': 2,
         'dayTripList': 
        [
            
            {
                'tripDay': '20240823',
                 'dayTripCnt': 4,
                 'tripDrvTime': 29,
                 'tripIdleTime': 0,
                 'tripDist': 15,
                 'tripAvgSpeed': 25.5,
                 'tripMaxSpeed': 70,
                 'tripList': 
                [
                    
                    {
                        'tripTime': '112146',
                         'tripDrvTime': 15,
                         'tripIdleTime': 0,
                         'tripDist': 8,
                         'tripAvgSpeed': 38,
                         'tripMaxSpeed': 65
                    },
                     
                    {
                        'tripTime': '105021',
                         'tripDrvTime': 3,
                         'tripIdleTime': 0,
                         'tripDist': 0,
                         'tripAvgSpeed': 21,
                         'tripMaxSpeed': 30
                    },
                     
                    {
                        'tripTime': '105010',
                         'tripDrvTime': 0,
                         'tripIdleTime': 0,
                         'tripDist': 0,
                         'tripAvgSpeed': 0,
                         'tripMaxSpeed': 0
                    },
                     
                    {
                        'tripTime': '101605',
                         'tripDrvTime': 11,
                         'tripIdleTime': 0,
                         'tripDist': 7,
                         'tripAvgSpeed': 43,
                         'tripMaxSpeed': 70
                    }
                ]
            }
        ]
    },
     'msgId': '260eed90-6182-11ef-a66f-163a59e3fcee'
}

@ZuinigeRijder
Copy link
Collaborator Author

ZuinigeRijder commented Aug 24, 2024

Relevant debug.py output for HyundaiBlueLinkAPIUSA.py

GET /ac/v2/ts/alerts/maintenance/evTripDetails

{
    'tripdetails': 
    [
        
        {
            'distance': 8,
             'odometer': 
            {
                'value': 4620.3
            },
             'accessories': 110,
             'totalused': 1927,
             'realtotalpwrcsp': 2000,
             'regen': 897,
             'avgspeed': 
            {
                'unit': 1,
                 'value': 42.0
            },
             'maxspeed': 
            {
                'unit': 1,
                 'value': 69.0
            },
             'climate': 128,
             'drivetrain': 1689,
             'startdate': '2024-08-21 11:31:25.0',
             'mileagetime': 
            {
                'unit': 3,
                 'value': 706.0
            },
             'duration': 
            {
                'unit': 3,
                 'value': 820
            },
             'batterycare': 0
        },
         
        {
            'distance': 0,
             'odometer': 
            {
                'value': 4611.9
            },
             'accessories': 40,
             'totalused': 175,
             'realtotalpwrcsp': 0,
             'regen': 168,
             'avgspeed': 
            {
                'unit': 1,
                 'value': 13.0
            },
             'maxspeed': 
            {
                'unit': 1,
                 'value': 32.0
            },
             'climate': 27,
             'drivetrain': 108,
             'startdate': '2024-08-21 10:57:36.0',
             'mileagetime': 
            {
                'unit': 3,
                 'value': 191.0
            },
             'duration': 
            {
                'unit': 3,
                 'value': 251
            },
             'batterycare': 0
        },
         
        {
            'distance': 0,
             'odometer': 
            {
                'value': 4611.2
            },
             'accessories': 20,
             'totalused': 28,
             'realtotalpwrcsp': 0,
             'regen': 0,
             'avgspeed': 
            {
                'unit': 1,
                 'value': 0.0
            },
             'maxspeed': 
            {
                'unit': 1,
                 'value': 0.0
            },
             'climate': 8,
             'drivetrain': 0,
             'startdate': '2024-08-21 10:56:34.0',
             'mileagetime': 
            {
                'unit': 3,
                 'value': 0.0
            },
             'duration': 
            {
                'unit': 3,
                 'value': 60
            },
             'batterycare': 0
        },
         
        {
            'distance': 9,
             'odometer': 
            {
                'value': 4611.2
            },
             'accessories': 120,
             'totalused': 1455,
             'realtotalpwrcsp': 1000,
             'regen': 1521,
             'avgspeed': 
            {
                'unit': 1,
                 'value': 26.0
            },
             'maxspeed': 
            {
                'unit': 1,
                 'value': 63.0
            },
             'climate': 101,
             'drivetrain': 1234,
             'startdate': '2024-08-21 09:24:55.0',
             'mileagetime': 
            {
                'unit': 3,
                 'value': 1268.0
            },
             'duration': 
            {
                'unit': 3,
                 'value': 1438
            },
             'batterycare': 0
        }
    ]
}

You see that the trip info is available in the output and that the daily_stats is NOT cumulative. Also it is a getter, so I do not know if it is possible to asks for months/days/tripinfo in the past?

@ZuinigeRijder
Copy link
Collaborator Author

@DanielRussell You made the changes for daily_stats in HyundaiBlueLinkAPIUSA.py. Do you know if it is possible to ask for trip info for a specific day in the Hyundai App? And if yes, what API is called with which parameters?

@gyveri
Copy link

gyveri commented Aug 24, 2024

I took a look at the extract from the HyundaiBlueLinkAPIUSA.py output of debug.py that you posted above. It contains an entry for each of the four trips I took on 21Aug. Yesterday morning, I took over 6 trips. When I ran debug.py today, the output contained an entry for only the four most-recent trips. There were no entries for any of the earlier trips I took yesterday.
It appears that. in response to the GET /ac/v2/ts/alerts/maintenance/evTripDetails command, the api retrieves the trip data for only the four most-recent trips the car has taken, even if the trips were taken the previous day (or earlier, maybe). This corresponds to the trip data that's displayed in the BlueLink app at Vehicle Status/EV Trip Details and to the blocks of four trip data that repeat in monitor.dailystats.csv .
Let me know if you'd like me to send you a copy of yesterday's debug file to your personal email.

@ZuinigeRijder
Copy link
Collaborator Author

@gyveri Yes, mail me the debug.py output, maybe I see different things.

Can you also post here a screenshot of the USA Hyundai Bluelink App for the trip report? That gives me some insight how the Hyundai App is organized, like I did here.

So there is no calendar or month statistics or something similar in the USA Hyundai Bluelink App? I also do not see the trip info in this overview of USA Hyundai Bluelink App.

Otherwise the difference in daily_stats is really different than in the other Regions, like Europe.
Biggest difference is that currently the daily_stats for USA is not cumulative and so it seems only the last 4 trips. There is NO history in the hyundai_kia_connect_api, so to provide cumulative data seems impossible in the api. But Vehicle.day_trip_info could be added too, because the data seems to be available for the last 4 trips.....

However, hyundai_kia_connect_monitor stores the daily_stats data in csv files, so has history. So could for region USA compute the cumulative data. But that means a specialized treating of the daily_stats data.

@gyveri
Copy link

gyveri commented Aug 25, 2024

I've sent you the debug results file and screenshots you requested.
As I mentioned, the trip details in the debug file show only the last 4 trips I made last Friday. The several trips I made earlier are not shown. This is unfortunate on a day like last Friday when I made more than 4 trips in an hour as, with the script running once per hour, the data for the earlier trips would be lost. The odometer readings would enable one to compute the lost distance, but there are no cumulative energy meters that would enable the lost cumulative energy to be computed. Hyundai exacerbates this issue by its strict limit (20) on daily accesses, so once could not deal with this issue by running the script more often. Or is there another GET command that would retrieve data for a defined time range. I use such a command to retrieve data from my Rainforest electricity meter monitor.
It's inconvenient to have to treat the daily_stats data differently, depending on region, but monitor.cfg has region data, so selection of the treatment of the daily_stats data could be automated.

@ZuinigeRijder
Copy link
Collaborator Author

@gyveri Thanks for the debug.py output and screenshots. Indeed it looks like only the last 4 recent trips can be shown and retrieved. And you are right that with hyundai_kia_connect_monitor you can miss trips, if you do more than 4 trips before you ask for the latest trip values. But it is better than nothing ;-)

I was also wondering why GET /ac/v2/ts/alerts/maintenance/evTripDetails is called twice in debug.output. I have to look into more detail in HyundaiBlueLinkAPIUSA.py why this is the case.

Indeed hyundai_kia_connect_monitor knows the region, so can handle the daily_stats data differently.
So 2 things needs to be done:

  1. Besides Vehicle.daily_stats, also Vehicle.month_trip_info and Vehicle.day_trip_info must be filled in HyundaiBlueLinkAPIUSA.py
  2. hyundai_kia_connect_monitor should handle Vehicle.daily_stats differently (compute cumulative with the history?), probably not needed for Vehicle.day_trip_info, as far as I can now see.

Maybe I should start with 2. to have the daily_stats functionality handled correctly and then 1????

@cdnninja
Copy link
Collaborator

My two cents is that if corrective logic is needed for the region if possible I would love to see it added here to the API. That way it normalizes the data between regions for others who consume this.

@ZuinigeRijder
Copy link
Collaborator Author

@cdnninja Yes, I want the API to be the same. However, there is a difference I cannot solve. The Vehicle.daily_stats is cumulative per day (one entry per day) for the other regions. Region USA it can have several entries for the same day, not cumulative (so the data is actually per trip). Also the max number of daily_stats entries is 4, whereas for the other regions it can be 30 days.

Computing the cumulative for USA is not possible, because when there are more trips than 4 on one day, then the cumulative data cannot be computed.

So the idea is for USA to just have the daily_stats data as is now, without the cumulative part. I think I can make the trip data consistent with the other regions, as far as I could see the necessary data is available, although also only for the last 4 trips.....

@gyveri
Copy link

gyveri commented Aug 26, 2024

"Computing the cumulative for USA is not possible, because when there are more trips than 4 on one day, then the cumulative data cannot be computed."
Here's a copy of part of monitor.dailystats.csv for 23 August, the day on which my car did many short trips.
20240823 11:00, 0, km, 11, 0, 1, 0, 10, 0
20240823 11:00, 0, km, 23, 0, 0, 3, 20, 0
20240823 11:00, 4, km, 928, 687, 784, 64, 80, 0
20240823 11:00, 0, km, 37, 12, 12, 5, 20, 0
20240823 12:00, 0, km, 147, 139, 54, 33, 60, 0
20240823 12:00, 4, km, 1018, 713, 901, 47, 70, 0
20240823 12:00, 0, km, 29, 0, 0, 9, 20, 0
20240823 12:00, 0, km, 30, 0, 3, 7, 20, 0
20240823 13:00, 0, km, 147, 139, 54, 33, 60, 0
20240823 13:00, 4, km, 1018, 713, 901, 47, 70, 0
20240823 13:00, 0, km, 29, 0, 0, 9, 20, 0
20240823 13:00, 0, km, 30, 0, 3, 7, 20, 0
20240823 14:00, 0, km, 147, 139, 54, 33, 60, 0
20240823 14:00, 4, km, 1018, 713, 901, 47, 70, 0
20240823 14:00, 0, km, 29, 0, 0, 9, 20, 0
20240823 14:00, 0, km, 30, 0, 3, 7, 20, 0
20240823 15:00, 0, km, 147, 139, 54, 33, 60, 0
20240823 15:00, 4, km, 1018, 713, 901, 47, 70, 0
20240823 15:00, 0, km, 29, 0, 0, 9, 20, 0
20240823 15:00, 0, km, 30, 0, 3, 7, 20, 0
You'll see that it contains data for 9 distinct trips before the data for the final 4 trips starts to repeat every hour. So, good news, it's not a maximum of 4 trips on one day, it's a maximum of 4 trips between successive readings (4 trips in one hour in the above example).
So the process to generate daily data needs to accumulate data that's fresh for the day, starting with the data for which the date in the timestamp changes, but to ignore data that a repeat of data that's already been accumulated.
It also needs to show the appropriate region-dependent unit for the distance_unit.
Let me know if you need a larger sample of monitor.dailystats.csv

@DanielRussell
Copy link
Contributor

So the process to generate daily data needs to accumulate data that's fresh for the day, starting with the data for which the date in the timestamp changes, but to ignore data that a repeat of data that's already been accumulated.
It also needs to show the appropriate region-dependent unit for the distance_unit.

I'll try to take a look at this in the next few days.

I wrote two simple scripts to solve this use case for myself:

  • fetch.py pulls all the data from the Hyundai API and dumps it into a timestamp'd JSON file (output/vehicles_{now.strftime('%Y%m%d%H%M%S')}.json). This is invoked from cron.
  • load.py loads all the JSON files into sqlite. I run this by hand any time I want to look at the data, but it could easily be combined with fetch.py

I'll use SQL to query the data, roll up stats, etc.

I don't look at the data very often, so I haven't bothered trying to import into a spreadsheet or make a Web UI.

I'm happy to share if there's interest.

@ZuinigeRijder
Copy link
Collaborator Author

"Computing the cumulative for USA is not possible, because when there are more trips than 4 on one day, then the cumulative data cannot be computed." ..... You'll see that it contains data for 9 distinct trips before the data for the final 4 trips starts to repeat every hour. So, good news, it's not a maximum of 4 trips on one day, it's a maximum of 4 trips between successive readings (4 trips in one hour in the above example). So the process to generate daily data needs to accumulate data that's fresh for the day, starting with the data for which the date in the timestamp changes, but to ignore data that a repeat of data that's already been accumulated. It also needs to show the appropriate region-dependent unit for the distance_unit. Let me know if you need a larger sample of monitor.dailystats.csv

Yes, in hyundai_kia_connect_monitor this is possible, but I answered the question of @cdnninja if it was possible to solve at hyundai_kia_connect_api, but there is no history possible (hyundai_kia_connect_api is stateless). So the only way to solve the cumulative part is at the client of the hyundai_kia_connect_api. I do not think adding state to hyundai_kia_connect_api is the way to go.

@ZuinigeRijder
Copy link
Collaborator Author

ZuinigeRijder commented Aug 27, 2024

@DanielRussell This functionality is available in hyundai_kia_connect_monitor, but need to do something special for HyundaiBlueLinkAPIUSA.py to compute the cumulative data with the available history in hyundai_kia_connect_monitor.

@gyveri
Copy link

gyveri commented Aug 28, 2024

"Computing the cumulative for USA is not possible, because when there are more trips than 4 on one day, then the cumulative data cannot be computed."
Here's a copy of part of monitor.dailystats.csv for 23 August, the day on which my car did many short trips.
20240823 11:00, 0, km, 11, 0, 1, 0, 10, 0
20240823 11:00, 0, km, 23, 0, 0, 3, 20, 0
20240823 11:00, 4, km, 928, 687, 784, 64, 80, 0
20240823 11:00, 0, km, 37, 12, 12, 5, 20, 0
20240823 12:00, 0, km, 147, 139, 54, 33, 60, 0
20240823 12:00, 4, km, 1018, 713, 901, 47, 70, 0
20240823 12:00, 0, km, 29, 0, 0, 9, 20, 0
20240823 12:00, 0, km, 30, 0, 3, 7, 20, 0
20240823 13:00, 0, km, 147, 139, 54, 33, 60, 0
20240823 13:00, 4, km, 1018, 713, 901, 47, 70, 0
20240823 13:00, 0, km, 29, 0, 0, 9, 20, 0
20240823 13:00, 0, km, 30, 0, 3, 7, 20, 0
20240823 14:00, 0, km, 147, 139, 54, 33, 60, 0
20240823 14:00, 4, km, 1018, 713, 901, 47, 70, 0
20240823 14:00, 0, km, 29, 0, 0, 9, 20, 0
20240823 14:00, 0, km, 30, 0, 3, 7, 20, 0
20240823 15:00, 0, km, 147, 139, 54, 33, 60, 0
20240823 15:00, 4, km, 1018, 713, 901, 47, 70, 0
20240823 15:00, 0, km, 29, 0, 0, 9, 20, 0
20240823 15:00, 0, km, 30, 0, 3, 7, 20, 0
You'll see that it contains data for 9 distinct trips before the data for the final 4 trips starts to repeat every hour. So, good news, it's not a maximum of 4 trips on one day, it's a maximum of 4 trips between successive readings (4 trips in one hour in the above example).
So the process to generate daily data needs to accumulate data that's fresh for the day, starting with the data for which the date in the timestamp changes, but to ignore data that a repeat of data that's already been accumulated.
It also needs to show the appropriate region-dependent unit for the distance_unit.
Let me know if you need a larger sample of monitor.dailystats.csv

@gyveri
Copy link

gyveri commented Aug 28, 2024

I took a further look at the way data is added to monitor.dailystats.csv. As noted above, data for the 4 most-recent trips is added to monitor.dailystats.csv on every update, e.g., every hour. This continues until data for a different date is received. This resets all four data slots and stores the new data. Of course, if the new data covers more than 4 trips, only data for the most-recent 4 trips is stored. The new data (for 1, 2, 3 or 4 trips) then repeats on every update unless data for one or more (n) new trips is received, in which case, data for the n oldest trips is removed and the new data is appended to the surviving older data.
The accumulation process for a given date should ignore data with the previous day's date. On each update, data with the day's date should be tested to determine whether it's been received previously. If it has not, it should be added to the accumulators. Because the updates only contain 4 sets of possibly previous data, the testing process should not be too burdensome

@ZuinigeRijder
Copy link
Collaborator Author

ZuinigeRijder commented Aug 28, 2024

@gyveri I have a patch which will fix the miles in monitor.dailystats.csv (fix in hyundai_kia_connect_api) and also fixes the multiple adding of entries to monitor.dailystats.csv in monitor.py (I hope, please test). I updated dailystats.py to compute the cumulative day values from monitor.dailystats.csv for region USA.

Best is to start with an empty monitor.dailystats.csv.

Just copy the files in the zip over the existing files.......
usapatch.zip

Note that if this all works, the next step would be to add support for the trip info in hyundai_kia_connect_api for HyundaiBlueLinkAPIUSA.py

@gyveri
Copy link

gyveri commented Aug 28, 2024

Done.

@gyveri
Copy link

gyveri commented Aug 28, 2024

copy of monitor.dailystats.csv attached. Timestamps are weird, as it's 11:05 as I write this. First run of the script would have been at 10:00, second run at 11:00. Car has been in garage, key off, all day today. Departing on trips soon. Will send u an update when I get home in about 4 hours.
monitor.dailystats.csv

@gyveri
Copy link

gyveri commented Aug 28, 2024

I've attached the version of monitor.dailystats.csv saved at 16:00 PDT.
Both trips appear to be recorded accurately. My only quibble is that the timestamps appear to be start-of-trip times, whereas all the other parameters are end-of-trip parameters.
BTW, the first four rows are the four rows captured yesterday, and the timestamps are correct for these data.
monitor.dailystats.csv

@ZuinigeRijder
Copy link
Collaborator Author

ZuinigeRijder commented Aug 29, 2024

Ok, so it seems to work.

The date/time in monitor.dailystats.csv is only meant for avoiding adding duplicate entries, actually the other regions do NOT fill a time in Vehicle.daily_stats and the csv file does contain then the time when the data was added by monitor.py.

HyundaiBlueLinkAPIUSA.py does indeed fill startdate (I did not change that). This does also make sense, I think, because what happens when you start a trip before midnight and end after midnight? The associated trip data is from before midnight I expect?

The call "GET /ac/v2/ts/alerts/maintenance/evTripDetails" gives startDate and duration (like other regions for tripdata). So I think it is more consistent how it is now and the trips are put on the day where it started.

If you agree, I can make a pull request for the fix of miles instead of km in hyundai_kia_connect_api and the changes for hyundai_kia_connect_monitor.

Thereafter I can implement the trip data for HyundaiBlueLinkAPIUSA.py

@gyveri
Copy link

gyveri commented Aug 29, 2024

Yes, your modifications appear to work. Thank you for doing this. And the additional rows in today's monitor.dailystats.csv contain only the data for the 4 trips I took this morning (no hangovers of yesterday's data).
monitor.dailystats.csv
I have a couple of additional requests:

  1. When we ran debug.py last week, I noticed that the type of the distance data included in the results was float, not integer. May I suggest that the type of the distance data in monitor.dailystats.csv (and elswhere) be float, rather than integer. That would enable short trips to be represented accurately. Notice that the last 2 trips I took this morning had a distance of 0. This is incorrect. In the 3rd trip, I went from home to the supermarket (~1 mile), and in the 4th trip, ! went home from the supermarket by a different route (~0.7 mile).
  2. The energy numbers don't add up. During yesterday's 26- and 25-mile trips, the traction battery SOC changed by 17%, which corresponds to about 12.7 kWh, which agrees fairly well with the sum of the total consumption (12.1 kWh). Moreover, for each trip, the sum of the engine-, climate-, electronics- and battery care-consumptions on each trip agrees exactly with the total consumed for the trip. This exact agreement suggests one of the consumptions is calculated by subtracting the sum of the other consumptions from the total consumption. But the calculation appears to ignore the regenerated energy, which must be consumed somewhere.

@ZuinigeRijder
Copy link
Collaborator Author

@gyveri For 1. I see the distance-data is integer, not as float, in your debug.py output and also in my debug.py output for region Europe.

Extract of one of your debug.py output (distance is always a whole number):

GET /ac/v2/ts/alerts/maintenance/evTripDetails
...
{
            'distance': 4,
             'odometer': 
            {
                'value': 4637.9
            },
             'accessories': 70,
             'totalused': 1018,
             'realtotalpwrcsp': 1000,
             'regen': 713,
             'avgspeed': 
            {
                'unit': 1,
                 'value': 31.0
            },
             'maxspeed': 
            {
                'unit': 1,
                 'value': 69.0
            },
             'climate': 47,
             'drivetrain': 901,
             'startdate': '2024-08-23 11:16:41.0',
             'mileagetime': 
            {
                'unit': 3,
                 'value': 521.0
            },
             'duration': 
            {
                'unit': 3,
                 'value': 587
            },
             'batterycare': 0
        },

For 2. I still do not know how the board computer consumption matches the computed one. I introduced a setting "include_regenerate_in_consumption = False" in monitor.cfg. You can set this to True. However, I think this is also not the way to compute the consumption figures. I had good results with long trips, but short trips are really off. And it does not help that the Bluelink server only returns the distance as integer, so especially for small trips there can be a huge difference.....So only long trips should be compared for checking the consumption.

I am starting to think the consumption figure in the boardcomputer is corrected with an efficiency number, like 1 kWh energy gives 0.9 kWh real energy (losses of converting battery kWh by the car). So I am thinking of introducing an efficiency configuration factor in hyundai_kia_connect_monitor, e.g. 0.9. So 10% of the energy is lost in conversion and is used in consumption calculation.

@gyveri
Copy link

gyveri commented Aug 30, 2024

Sorry - I identified the wrong parameter. Yes, the distance is an integer, but each block of evTripDetails also includes an odometer value that is type float. Wouldn't computing the trip distance from the odometer values in consecutive blocks of evTripDetails give a more useful result than using the pre-computed integer trip distance, especially for short trips?

I agree that regeneration should not be included in the consumption calculation provided that the consumption calculation uses the total_consumption. However, I think that at least one of the other consumption values (engine, climate, electronics, battery care) is incorrect because the sum of these values should equal the sum of total consumption and regeneration, and not total consumption alone. The regeneration energy doesn't just disappear.

@ZuinigeRijder
Copy link
Collaborator Author

Yeah, the USA server returns a combination of day stats and trip info. However, for the daily_stats for the other regions, no odometer is returned. I do not want to deviate in the hyundai_kia_connect_api for the interface, so you have to do with the distance, like the other regions, especially, because the history of daily stats is not always available in hyundai_kia_connect_api for USA, so also there the distance should not be computed, but just taken over, with, unfortunately no decimal point.

I do not have a good clue about the consumption calculation in respect how the regen fits in. However, looking at my data, it seems that the reported consumption of the boardcomputer is about 10% less than the calculations.

@gyveri
Copy link

gyveri commented Sep 5, 2024

The revised scripts you sent me on 28 August have now been running for over a week. The revised scripts appear to have addressed the issues caused by the differences between KiaUvoApiEU and HyundaiBlueLinkAPIUSA.
I have found one issue that occurs when the car is charged on a day on which it is not driven. On 2 September, I charged the car but did not drive it. The amount of the charge the car received on that data is shown in summary.day.csv and summary.charge.csv. But monitor.dailystats spreadsheet has no entry for that date. Consequently, the spreadsheet does not show the amount of charge the car received that day.
Regarding odometer readings, I understand your desire to minimize difference between the ways in which the European and U.S. apis are handled. But I ask that you reconsider. The mile is almost twice as far as the kilometer, so the chance of having a zero-distance trip is substantially greater in the US than in Europe. Would it be possible to add to monitor.py code that would address this issue. The code would begin with
if REGION == 3:
The code would pull the odometer reading from the EV trip information and replace the integer odometer reading with the odometer reading from the EV trip information. The code would also recompute the distance in each EV trip information with corresponding between the odometer readings in the EV trip information for the trip and for the previous trip to generate a trip distance with a resolution of a tenth of a mile. This would result in a much lower chance of a zero-length trip.

@ZuinigeRijder
Copy link
Collaborator Author

@gyveri The dailystats.py spreadsheet is for showing the dailystats and trip information received from the server. And I also show some information from summary.py, when there is dailystats data.

The amount of charge received per day can be seen in summary.py spreadsheet, including current SOC%.

Did you not configure/generate the summary.py spreadsheet?
I look regularly at both.....they serve a different purpose.

summary py_GoogleSpreadsheet

@ZuinigeRijder
Copy link
Collaborator Author

@gyveri I also made an attempt to also fill vehicle.month_trip_info and vehicle.day_trip_info, instead of only vehicle.daily_stats for HyundaiBlueLinkAPIUSA.py. Can you try out the patch? If you regularly call monitor.py it should fill the trips over time, beside the daily stats.

Note that I used a trick to avoid calling GET /ac/v2/ts/alerts/maintenance/evTripDetails each time, by storing the state in vehicle.data["filled_trips"].

HyundaiBlueLinkAPIUSA.zip

@gyveri
Copy link

gyveri commented Sep 6, 2024

I have installed the revised HyundaiBlueLinkAPIUSA. I'll let you know the results later in the day. monitor.py runs hourly during the day.
When I started running monitor.py, I configured the summary spreadsheet and I have been using it ever since. run_monitor_once.sh runs hourly during the day, so I assume summary.py runs hourly. The charging info for Sep 2 appears in that spreadsheet OK. The daily charge info also appears (in parentheses) in the monitor.dailystats spreadsheet, but not if the car has not made any trips that day. The display of charge info being conditional on the car making a trip on the same day seems illogical to me. If nothing happens to the car in a given day, I can understand omitting that day from the spreadsheet. IMO, charging is something that happens to the car in the day, so data for the day should be displayed, i.e., the charging info together with the appropriate usage info (all zeroes).

@ZuinigeRijder
Copy link
Collaborator Author

@gyveri Currently I loop over the monitor.dailystats.csv data and search some data from the other csv files. For me it seems not logical to display all empty day data with no trips, just to show only the charge info in dailystats spreadsheet. Besides that, implementing this is not easy. So for the charge info you have to look at the summary spreadsheet......

@gyveri
Copy link

gyveri commented Sep 6, 2024

Back from taking 4 trips. Where might I find files named vehicle.month_trip_info, vehicle.day_trip_info, and vehicle.daily_stats? I've been unable to find files with these names in my hyundai_kia_connect_monitor folder.

@ZuinigeRijder
Copy link
Collaborator Author

That are not the files, but the variables inside Vehicle.py which monitor.py uses, monitor.py calls method VehicleManager.update_month_trip_info() and VehicleManager.update_day_trip_info() and thereafter writes new trip data to monitor.tripinfo.csv. This csv file is read by dailystats.py and the trips should appear in the dailystats spreadsheet (if all works).

Note that when you run debug.py on a day when there are trips made, it should also show trip information from that day in the output (if it works).

@gyveri
Copy link

gyveri commented Sep 7, 2024

Many thanks for the explanation.
After my 4 trips yesterday, monitor.tripinfo.csv is unchanged - just the headers.
The aggregate of the 4 trips appears in the dailystats spreadsheet, but the mileage shown is incorrect (14 miles vs 17 miles yesterday's odometer - previous day's odometer).
I've sent you the debug.py results to your personal email. It should cover the 4 trips I took yesterday A -B 4.3 mi, B-C 4.6 mi, C-D 7.8 mi, D-A 50 feet (16 meters).

@ZuinigeRijder
Copy link
Collaborator Author

@gyveri That is really strange, because the dailystats spreadsheet does use the trip information inside monitor.tripinfo.csv. So if the trip information is not in there, it would not show this information in the dailystats spreadsheet. Can you post a screenshot of the dailystats spreadsheet?

Note that I received the email with title "debug.py results 20240907", but there was no attachment in it?

@ZuinigeRijder
Copy link
Collaborator Author

Thanks for the testing and debug.py output. In the latest debug.py output I see that the vehicle._month_trip_info is filled, but vehicle_day_trip_info not. So apparently I have done something wrong in the patch. I have to look carefully at the provided patch again, to see where I did something wrong with the programming....especially because I cannot test.

Note that in the dailystats spreadsheet some cumulative trip data is shown, but NOT all the trips per day, because of the problem above.

@ZuinigeRijder
Copy link
Collaborator Author

@gyveri I looked at the code and could not find the problem. I added debug statements, so if you can run debug.py again on the same day you did some trips and mail me the output logging? Maybe that gives me a clue.....just overwrite the two files in the zip.

hyundai_kia_connect_api.zip

@ZuinigeRijder
Copy link
Collaborator Author

@gyveri I did receive the debug.py output and mailed you back. This is what I mailed.

Hmmm, the day results are now filled:

_day_trip_info=DayTripInfo
        (
            yyyymmdd='20240912',
             summary=TripInfo
            (
                hhmmss=None,
                 drive_time=1159,
                 idle_time=452,
                 distance=6,
                 avg_speed=7.7,
                 max_speed=42
            ),
             trip_list=
            [
                TripInfo
                (
                    hhmmss='105922',
                     drive_time=591,
                     idle_time=27,
                     distance=3,
                     avg_speed=21.0,
                     max_speed=42
                ),
                 TripInfo
                (
                    hhmmss='094228',
                     drive_time=550,
                     idle_time=350,
                     distance=3,
                     avg_speed=23.0,
                     max_speed=41
                ),
                 TripInfo
                (
                    hhmmss='080149',
                     drive_time=18,
                     idle_time=75,
                     distance=0,
                     avg_speed=1.0,
                     max_speed=1
                )
            ]
        ),

Question is if monitor.tripinfo.csv is now filled or not? If yes, are those 3 trips showing in the dailystats spreadsheet?
Can you send the monitor.tripinfo.csv?
Can you delete the monitor.tripinfo.csv file and see if thereafter trips appear?

If still no trips appear, can you run monitor.py on a day with trips with debug output via the command:

python monitor.py debug

And mail me the standard output and error output?

Thanks,
Zuinige Rijder Rick.

@gyveri
Copy link

gyveri commented Sep 17, 2024

This morning, I deleted the only-headings monitor.tripinfo.csv and went for a short (but >1 mile) drive. Now monitor.tripinfo.csv has info for the trips I took Friday afternoon, yesterday and today.
This trip info is also shown on the monitor.dailystats spreadsheet.
Meanwhile, the hyunday-kia-connect-monitor spreadsheet has not updated since 14:00 PDT Friday, even though monitor.csv has data for the missing days. Do you have any suggestion as to what might be causing this issue?
monitor.tripinfo.csv

@ZuinigeRijder
Copy link
Collaborator Author

Ah, good to hear that it is now working and monitor.tripinfo.csv is now containing the trips. So apparently the monitor.tripinfo.csv must be empty before adding the first trip. Actually this is a small problem in monitor.py, but this is only a rare case, when tripinfo was not working the first time the header was added to monitor.tripinfo.csv.

Strange that the hyundai-kia-connect-monitor spreadsheet was not updated. Is the standard output and error output (in run_monitor_once.summary.log) also not up-to-date? Sometimes, in Android, you have to refresh the whole spreadsheet, because there are to many updates. But it can also be that something else. Can you have a look into the redirected output:

/usr/bin/python -u ~/hyundai_kia_connect_monitor/summary.py sheetupdate > run_monitor_once.summary.log 2>&1

@ZuinigeRijder
Copy link
Collaborator Author

@cdnninja
Because the local changes in HyundaiBlueLinkAPIUSA.py are working, I created a Pull Request: #632

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants