From 949affec1f807cc1ed323496b2f6a10d22de4c37 Mon Sep 17 00:00:00 2001 From: Carsten Schmiemann Date: Sun, 6 Nov 2022 02:40:10 +0100 Subject: [PATCH] Sync to original project --- .../ovms_location/src/ovms_location.cpp | 2 +- OVMS.V3/components/ovms_ota/src/ovms_ota.cpp | 6 +- .../ovms_server_v3/src/ovms_server_v3.cpp | 205 ++++++++++++++++- OVMS.V3/components/ovms_tls/component.mk | 2 +- OVMS.V3/components/ovms_tls/src/ovms_tls.cpp | 4 - .../ovms_webserver/docs/bms-cell-info.odg | Bin 0 -> 24422 bytes .../ovms_webserver/docs/bms-cell-monitor.rst | 1 + .../components/ovms_webserver/src/web_cfg.cpp | 4 +- .../ovms_webserver/src/web_cfg_init.cpp | 13 +- OVMS.V3/components/vehicle/vehicle.cpp | 2 + OVMS.V3/components/vehicle/vehicle.h | 10 +- OVMS.V3/components/vehicle/vehicle_bms.cpp | 206 ++++++++++++++---- OVMS.V3/components/vehicle/vehicle_shell.cpp | 9 +- .../src/vehicle_renaultzoe_ph2_obd.cpp | 4 +- 14 files changed, 388 insertions(+), 80 deletions(-) create mode 100644 OVMS.V3/components/ovms_webserver/docs/bms-cell-info.odg diff --git a/OVMS.V3/components/ovms_location/src/ovms_location.cpp b/OVMS.V3/components/ovms_location/src/ovms_location.cpp index 860834b..ddf4988 100644 --- a/OVMS.V3/components/ovms_location/src/ovms_location.cpp +++ b/OVMS.V3/components/ovms_location/src/ovms_location.cpp @@ -753,7 +753,7 @@ void OvmsLocations::UpdatedVehicleOn(OvmsMetric* metric) void OvmsLocations::UpdateParkPosition() { OvmsRecMutexLock lock(&m_park_lock); - + bool caron = StdMetrics.ms_v_env_on->AsBool(); if (caron) { diff --git a/OVMS.V3/components/ovms_ota/src/ovms_ota.cpp b/OVMS.V3/components/ovms_ota/src/ovms_ota.cpp index 723dfa2..ecfb4a0 100644 --- a/OVMS.V3/components/ovms_ota/src/ovms_ota.cpp +++ b/OVMS.V3/components/ovms_ota/src/ovms_ota.cpp @@ -288,7 +288,7 @@ void ota_flash_http(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int arg url = MyConfig.GetParamValue("ota","server"); if (url.empty()) - url = "ovms-ota.bit-cloud.de"; + url = "api.openvehicles.com/firmware/ota"; url.append("/"); url.append(GetOVMSProduct()); @@ -830,7 +830,7 @@ void OvmsOTA::GetStatus(ota_info& info, bool check_update /*=true*/) std::string tag = MyConfig.GetParamValue("ota","tag"); std::string url = MyConfig.GetParamValue("ota","server"); if (url.empty()) - url = "ovms-ota.bit-cloud.de"; + url = "api.openvehicles.com/firmware/ota"; url.append("/"); url.append(GetOVMSProduct()); url.append("/"); @@ -1029,7 +1029,7 @@ bool OvmsOTA::AutoFlash(bool force) std::string tag = MyConfig.GetParamValue("ota","tag"); std::string url = MyConfig.GetParamValue("ota","server"); if (url.empty()) - url = "ovms-ota.bit-cloud.de"; + url = "api.openvehicles.com/firmware/ota"; url.append("/"); url.append(GetOVMSProduct()); diff --git a/OVMS.V3/components/ovms_server_v3/src/ovms_server_v3.cpp b/OVMS.V3/components/ovms_server_v3/src/ovms_server_v3.cpp index bdb027a..efd0cf6 100644 --- a/OVMS.V3/components/ovms_server_v3/src/ovms_server_v3.cpp +++ b/OVMS.V3/components/ovms_server_v3/src/ovms_server_v3.cpp @@ -282,14 +282,133 @@ void OvmsServerV3::TransmitModifiedMetrics() if (!m_mgconn) return; - OvmsMetric* metric = MyMetrics.m_first; - while (metric != NULL) + if (StandardMetrics.ms_v_bat_soc->IsModifiedAndClear(MyOvmsServerV3Modifier)) { - if (metric->IsModifiedAndClear(MyOvmsServerV3Modifier)) - { - TransmitMetric(metric); - } - metric = metric->m_next; + TransmitMetric(StandardMetrics.ms_v_bat_soc); + } + if (StandardMetrics.ms_v_charge_voltage->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_voltage); + } + if (StandardMetrics.ms_v_charge_current->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_current); + } + if (StandardMetrics.ms_v_charge_state->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_state); + } + if (StandardMetrics.ms_v_charge_substate->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_substate); + } + if (StandardMetrics.ms_v_charge_mode->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_mode); + } + if (StandardMetrics.ms_v_bat_range_ideal->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_bat_range_ideal); + } + if (StandardMetrics.ms_v_bat_range_est->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_bat_range_est); + } + if (StandardMetrics.ms_v_charge_climit->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_climit); + } + if (StandardMetrics.ms_v_charge_kwh->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_kwh); + } + if (StandardMetrics.ms_v_charge_timermode->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_timermode); + } + if (StandardMetrics.ms_v_charge_timerstart->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_timerstart); + } + if (StandardMetrics.ms_v_bat_cac->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_bat_cac); + } + if (StandardMetrics.ms_v_charge_duration_full->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_duration_full); + } + if (StandardMetrics.ms_v_charge_duration_range->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_duration_range); + } + if (StandardMetrics.ms_v_charge_duration_soc->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_duration_soc); + } + if (StandardMetrics.ms_v_charge_inprogress->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_inprogress); + } + if (StandardMetrics.ms_v_charge_limit_range->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_limit_range); + } + if (StandardMetrics.ms_v_charge_limit_soc->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_limit_soc); + } + if (StandardMetrics.ms_v_env_cooling->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_env_cooling); + } + if (StandardMetrics.ms_v_bat_range_full->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_bat_range_full); + } + if (StandardMetrics.ms_v_bat_power->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_bat_power); + } + if (StandardMetrics.ms_v_bat_voltage->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_bat_voltage); + } + if (StandardMetrics.ms_v_bat_soh->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_bat_soh); + } + if (StandardMetrics.ms_v_charge_power->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_power); + } + if (StandardMetrics.ms_v_charge_efficiency->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_charge_efficiency); + } + if (StandardMetrics.ms_v_bat_current->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_bat_current); + } + if (StandardMetrics.ms_v_bat_range_speed->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_bat_range_speed); + } + if (StandardMetrics.ms_v_tpms_pressure->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_tpms_pressure); + } + if (StandardMetrics.ms_v_tpms_temp->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_tpms_temp); + } + if (StandardMetrics.ms_v_tpms_health->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_tpms_health); + } + if (StandardMetrics.ms_v_tpms_alert->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(StandardMetrics.ms_v_tpms_alert); } } @@ -748,13 +867,25 @@ void OvmsServerV3::MetricModified(OvmsMetric* metric) { if (!StandardMetrics.ms_s_v3_connected->AsBool()) return; - if (m_streaming) + int now = StandardMetrics.ms_m_monotonic->AsInt(); + //ESP_LOGD(TAG, "now: %d, m_lasttx_stream: %d, m_streaming: %d", now, m_lasttx_stream, m_streaming); + if (StandardMetrics.ms_v_env_on->AsBool() && m_streaming && now > m_lasttx_stream+m_streaming) { OvmsMutexLock mg(&m_mgconn_mutex); if (!m_mgconn) return; - metric->ClearModified(MyOvmsServerV3Modifier); - TransmitMetric(metric); + //metric->ClearModified(MyOvmsServerV3Modifier); + + while (metric != NULL) + { + if (metric->IsModifiedAndClear(MyOvmsServerV3Modifier)) + { + TransmitMetric(metric); + } + metric = metric->m_next; + } + //TransmitMetric(metric); + m_lasttx_stream = now; } } @@ -817,13 +948,22 @@ void OvmsServerV3::EventListener(std::string event, void* data) */ void OvmsServerV3::ConfigChanged(OvmsConfigParam* param) { + ESP_LOGD(TAG, "--- ConfigChanged ---"); m_streaming = MyConfig.GetParamValueInt("vehicle", "stream", 0); + ESP_LOGD(TAG, "m_streaming: %d", m_streaming); m_updatetime_connected = MyConfig.GetParamValueInt("server.v3", "updatetime.connected", 60); + ESP_LOGD(TAG, "m_updatetime_connected: %d", m_updatetime_connected); m_updatetime_idle = MyConfig.GetParamValueInt("server.v3", "updatetime.idle", 600); + ESP_LOGD(TAG, "m_updatetime_idle: %d", m_updatetime_idle); m_updatetime_awake = MyConfig.GetParamValueInt("server.v3", "updatetime.awake", m_updatetime_idle); + ESP_LOGD(TAG, "m_updatetime_awake: %d", m_updatetime_awake); m_updatetime_on = MyConfig.GetParamValueInt("server.v3", "updatetime.on", m_updatetime_idle); + ESP_LOGD(TAG, "m_updatetime_on: %d", m_updatetime_on); m_updatetime_charging = MyConfig.GetParamValueInt("server.v3", "updatetime.charging", m_updatetime_idle); + ESP_LOGD(TAG, "m_updatetime_charging: %d", m_updatetime_charging); m_updatetime_sendall = MyConfig.GetParamValueInt("server.v3", "updatetime.sendall", 0); + ESP_LOGD(TAG, "m_updatetime_sendall: %d", m_updatetime_sendall); + ESP_LOGD(TAG, "--- ConfigChanged ---"); } void OvmsServerV3::NetUp(std::string event, void* data) @@ -929,12 +1069,55 @@ void OvmsServerV3::Ticker1(std::string event, void* data) } else if ((m_lasttx==0)||(now>(m_lasttx+next))) { + ESP_LOGD(TAG, "m_lasttx: %d next: %d, now: %d", m_lasttx, next, now); + ESP_LOGD(TAG, "m_updatetime_connected: %d m_updatetime_on: %d, m_updatetime_charging: %d", m_updatetime_connected, m_updatetime_on, m_updatetime_charging); + ESP_LOGD(TAG, "m_updatetime_awake: %d ", m_updatetime_awake); TransmitModifiedMetrics(); m_lasttx = m_lasttx_stream = now; } else if (m_streaming && caron && m_peers && now > m_lasttx_stream+m_streaming) { - // TODO: transmit streaming metrics + //Transmit important metrics while streaming + bool modified = + StandardMetrics.ms_v_pos_latitude->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_pos_longitude->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_pos_direction->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_pos_altitude->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_pos_gpslock->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_pos_gpssq->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_pos_gpsmode->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_pos_gpshdop->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_pos_satcount->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_pos_gpsspeed->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_pos_speed->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_env_drivemode->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_bat_power->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_bat_energy_used->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_bat_energy_recd->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_inv_power->IsModifiedAndClear(MyOvmsServerV3Modifier) | + StandardMetrics.ms_v_inv_efficiency->IsModifiedAndClear(MyOvmsServerV3Modifier); + + // Quick exit if nothing modified + if ((!modified)) return; + + TransmitMetric(StandardMetrics.ms_v_pos_latitude); + TransmitMetric(StandardMetrics.ms_v_pos_longitude); + TransmitMetric(StandardMetrics.ms_v_pos_direction); + TransmitMetric(StandardMetrics.ms_v_pos_altitude); + TransmitMetric(StandardMetrics.ms_v_pos_gpslock); + TransmitMetric(StandardMetrics.ms_v_pos_gpssq); + TransmitMetric(StandardMetrics.ms_v_pos_gpsmode); + TransmitMetric(StandardMetrics.ms_v_pos_gpshdop); + TransmitMetric(StandardMetrics.ms_v_pos_satcount); + TransmitMetric(StandardMetrics.ms_v_pos_gpsspeed); + TransmitMetric(StandardMetrics.ms_v_pos_speed); + TransmitMetric(StandardMetrics.ms_v_env_drivemode); + TransmitMetric(StandardMetrics.ms_v_bat_power); + TransmitMetric(StandardMetrics.ms_v_bat_energy_used); + TransmitMetric(StandardMetrics.ms_v_bat_energy_recd); + TransmitMetric(StandardMetrics.ms_v_inv_power); + TransmitMetric(StandardMetrics.ms_v_inv_efficiency); + m_lasttx_stream = now; } } diff --git a/OVMS.V3/components/ovms_tls/component.mk b/OVMS.V3/components/ovms_tls/component.mk index 1a17834..a7709f7 100644 --- a/OVMS.V3/components/ovms_tls/component.mk +++ b/OVMS.V3/components/ovms_tls/component.mk @@ -11,5 +11,5 @@ ifdef CONFIG_MG_ENABLE_SSL COMPONENT_SRCDIRS := src COMPONENT_ADD_INCLUDEDIRS := src COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive -COMPONENT_EMBED_FILES := trustedca/usertrust.crt trustedca/digicert_global.crt trustedca/starfield_class2.crt trustedca/baltimore_cybertrust.crt trustedca/isrg_x1.crt trustedca/ovms_ca.crt +COMPONENT_EMBED_FILES := trustedca/usertrust.crt trustedca/digicert_global.crt trustedca/starfield_class2.crt trustedca/baltimore_cybertrust.crt trustedca/isrg_x1.crt endif diff --git a/OVMS.V3/components/ovms_tls/src/ovms_tls.cpp b/OVMS.V3/components/ovms_tls/src/ovms_tls.cpp index 29c3602..64cdd34 100644 --- a/OVMS.V3/components/ovms_tls/src/ovms_tls.cpp +++ b/OVMS.V3/components/ovms_tls/src/ovms_tls.cpp @@ -164,10 +164,6 @@ void OvmsTLS::Reload() extern const unsigned char isrg_x1_end[] asm("_binary_isrg_x1_crt_end"); m_trustlist["ISRG X1 CA"] = new OvmsTrustedCert(isrg_x1, isrg_x1_end - isrg_x1); - extern const unsigned char ovms_ca[] asm("_binary_ovms_ca_crt_start"); - extern const unsigned char ovms_ca_end[] asm("_binary_ovms_ca_crt_end"); - m_trustlist["OVMS Bit-Cloud.de CA"] = new OvmsTrustedCert(ovms_ca, ovms_ca_end - ovms_ca); - // Add trusted certs on disk (/store/trustedca) DIR *dir; struct dirent *dp; diff --git a/OVMS.V3/components/ovms_webserver/docs/bms-cell-info.odg b/OVMS.V3/components/ovms_webserver/docs/bms-cell-info.odg new file mode 100644 index 0000000000000000000000000000000000000000..1643e9d701d30c60fd4a88d4dc936dd0de7dc422 GIT binary patch literal 24422 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

COTuFvvu%mE1g2C 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 literal 0 HcmV?d00001 diff --git a/OVMS.V3/components/ovms_webserver/docs/bms-cell-monitor.rst b/OVMS.V3/components/ovms_webserver/docs/bms-cell-monitor.rst index 6c1ec94..cce7b5d 100644 --- a/OVMS.V3/components/ovms_webserver/docs/bms-cell-monitor.rst +++ b/OVMS.V3/components/ovms_webserver/docs/bms-cell-monitor.rst @@ -158,3 +158,4 @@ Also keep in mind, not all deviations may be caused by actual battery issues. Voltage and temperature sensors can lose their calibration or become defective as well. + diff --git a/OVMS.V3/components/ovms_webserver/src/web_cfg.cpp b/OVMS.V3/components/ovms_webserver/src/web_cfg.cpp index 52abbb9..ae7649b 100644 --- a/OVMS.V3/components/ovms_webserver/src/web_cfg.cpp +++ b/OVMS.V3/components/ovms_webserver/src/web_cfg.cpp @@ -1406,7 +1406,6 @@ void OvmsWebServer::HandleCfgServerV2(PageEntry_t& p, PageContext_t& c) c.input_text("Server", "server", server.c_str(), "Enter host name or IP address", "

Public OVMS V2 servers:

" "
"); @@ -2650,7 +2649,6 @@ void OvmsWebServer::HandleCfgFirmware(PageEntry_t& p, PageContext_t& c) "

Automatic updates are normally only done if a wifi connection is available at the time. Before allowing updates via modem, be aware a single firmware image has a size of around 3 MB, which may lead to additional costs on your data plan.

"); c.print( "" - "" @@ -2661,7 +2659,7 @@ void OvmsWebServer::HandleCfgFirmware(PageEntry_t& p, PageContext_t& c) "" ); c.input_text("Update server", "server", server.c_str(), "Specify or select from list (clear to see all options)", - "

Default is https://ovms-ota.bit-cloud.de.

", + "

Default is https://api.openvehicles.com/firmware/ota.

", "list=\"server-list\""); c.input_text("Version tag", "tag", tag.c_str(), "Specify or select from list (clear to see all options)", "

Default is main for standard releases. Use eap (early access program) for stable or edge for bleeding edge developer builds.

", diff --git a/OVMS.V3/components/ovms_webserver/src/web_cfg_init.cpp b/OVMS.V3/components/ovms_webserver/src/web_cfg_init.cpp index b260510..33d094e 100644 --- a/OVMS.V3/components/ovms_webserver/src/web_cfg_init.cpp +++ b/OVMS.V3/components/ovms_webserver/src/web_cfg_init.cpp @@ -749,7 +749,7 @@ std::string OvmsWebServer::CfgInit3(PageEntry_t& p, PageContext_t& c, std::strin if (server.empty()) server = MyConfig.GetParamValue("ota", "server"); if (server.empty()) - server = "https://ovms-ota.bit-cloud.de"; + server = "https://api.openvehicles.com/firmware/ota"; MyOTA.GetStatus(info, true); @@ -843,8 +843,6 @@ std::string OvmsWebServer::CfgInit3(PageEntry_t& p, PageContext_t& c, std::strin c.panel_start("primary", "Step 3/5: Update Firmware"); c.form_start(p.uri); c.input_radio_start("Update server", "server"); - c.input_radio_option("server", "Europe, Germany (ovms-ota.bit-cloud.de)", - "https://ovms-ota.bit-cloud.de" , server == "https://ovms-ota.bit-cloud.de"); c.input_radio_option("server", "Asia-Pacific (openvehicles.com)", "https://api.openvehicles.com/firmware/ota" , server == "https://api.openvehicles.com/firmware/ota"); c.input_radio_option("server", "Europe (dexters-web.de)", @@ -952,10 +950,10 @@ std::string OvmsWebServer::CfgInit4(PageEntry_t& p, PageContext_t& c, std::strin // default data server = ota server: if (server.empty()) { server = MyConfig.GetParamValue("ota", "server"); - if (startsWith(server, "ovms-ota.bit-cloud.de")) - server = "ovms-server.bit-cloud.de"; - else + if (startsWith(server, "ovms.dexters-web.de")) server = "ovms.dexters-web.de"; + else + server = "api.openvehicles.com"; } } @@ -1036,9 +1034,6 @@ std::string OvmsWebServer::CfgInit4(PageEntry_t& p, PageContext_t& c, std::strin c.input_radio_start("OVMS data server", "server"); c.input_radio_option("server", "No server connection", "" , server == ""); - c.input_radio_option("server", - "Europe, Germany (ovms-server.bit-cloud.de) Registration", - "ovms-server.bit-cloud.de" , server == "ovms-server.bit-cloud.de"); c.input_radio_option("server", "Asia-Pacific (openvehicles.com) Registration", "api.openvehicles.com" , server == "api.openvehicles.com"); diff --git a/OVMS.V3/components/vehicle/vehicle.cpp b/OVMS.V3/components/vehicle/vehicle.cpp index 0195f22..05d77d9 100644 --- a/OVMS.V3/components/vehicle/vehicle.cpp +++ b/OVMS.V3/components/vehicle/vehicle.cpp @@ -90,6 +90,8 @@ OvmsVehicleFactory::OvmsVehicleFactory() OvmsCommand* cmd_bms = MyCommandApp.RegisterCommand("bms","BMS framework", bms_status, "", 0, 0, false); cmd_bms->RegisterCommand("status","Show BMS status",bms_status); + cmd_bms->RegisterCommand("temp","Show BMS temperature status",bms_status); + cmd_bms->RegisterCommand("volt","Show BMS voltage status",bms_status); cmd_bms->RegisterCommand("reset","Reset BMS statistics",bms_reset); cmd_bms->RegisterCommand("alerts","Show BMS alerts",bms_alerts); diff --git a/OVMS.V3/components/vehicle/vehicle.h b/OVMS.V3/components/vehicle/vehicle.h index 820735a..81061f8 100644 --- a/OVMS.V3/components/vehicle/vehicle.h +++ b/OVMS.V3/components/vehicle/vehicle.h @@ -155,6 +155,8 @@ struct DashboardConfig; #define VEHICLE_POLL_TYPE_OBDIIGROUP 0x21 // Custom: Read data by 8 bit PID #define VEHICLE_POLL_TYPE_OBDII_32 0x32 // Custom: VW routine control extension (8 bit PID) +#define VEHICLE_OBD_BROADCAST_MODULE_TX 0x7df +#define VEHICLE_OBD_BROADCAST_MODULE_RX 0x0 // A note on "PID" and their sizes here: // By "PID" for the service types we mean the part of the request parameters // after the service type that is reflected in _every_ valid response to the request. @@ -479,6 +481,12 @@ class OvmsVehicle : public InternalRamAllocated Range = 3, Performance = 4 } vehicle_mode_t; + enum class vehicle_bms_status_t + { + Both, + Voltage, + Temperature + }; public: vehicle_mode_t VehicleModeKey(const std::string code); @@ -694,7 +702,7 @@ class OvmsVehicle : public InternalRamAllocated void BmsGetCellDefaultThresholdsVoltage(float* warn, float* alert, float* maxgrad=NULL, float* maxsddev=NULL); void BmsGetCellDefaultThresholdsTemperature(float* warn, float* alert); void BmsResetCellStats(); - virtual void BmsStatus(int verbosity, OvmsWriter* writer); + virtual void BmsStatus(int verbosity, OvmsWriter* writer, vehicle_bms_status_t statusmode); virtual bool FormatBmsAlerts(int verbosity, OvmsWriter* writer, bool show_warnings); bool BmsCheckChangeCellArrangementVoltage(int readings, int readingspermodule = 0); bool BmsCheckChangeCellArrangementTemperature(int readings, int readingspermodule = 0); diff --git a/OVMS.V3/components/vehicle/vehicle_bms.cpp b/OVMS.V3/components/vehicle/vehicle_bms.cpp index 1c4861c..18c4366 100644 --- a/OVMS.V3/components/vehicle/vehicle_bms.cpp +++ b/OVMS.V3/components/vehicle/vehicle_bms.cpp @@ -550,13 +550,59 @@ void OvmsVehicle::BmsResetCellStats() BmsResetCellTemperatures(false); } -void OvmsVehicle::BmsStatus(int verbosity, OvmsWriter* writer) +template +INT round_up_div(INT value, INT divis) { + return (value + divis -1) / divis; + } + +void OvmsVehicle::BmsStatus(int verbosity, OvmsWriter* writer, vehicle_bms_status_t statusmode) + { + auto check_max_cols = [](int total_cols, int maximum) + { + if (maximum <= 1) + return 1; + if (total_cols <= maximum) + return total_cols; + if (maximum >= 4 && total_cols % 4 == 0) + return 4; + if (total_cols % 3 == 0) + return 3; + if (maximum >= 5 && total_cols % 5 == 0) + return 5; + return maximum; + }; + int c; - if ((! m_bms_has_voltages)||(! m_bms_has_temperatures)) + bool show_voltage = m_bms_has_voltages; + bool show_temperature = m_bms_has_temperatures; + switch (statusmode) { - writer->puts("No BMS status data available"); + case vehicle_bms_status_t::Both: + break; + case vehicle_bms_status_t::Voltage: + show_temperature = false; + break; + case vehicle_bms_status_t::Temperature: + show_voltage = false; + break; + } + if ((!show_voltage) && (!show_temperature)) + { + const char *datatype= "status"; + switch (statusmode) + { + case vehicle_bms_status_t::Both: + break; + case vehicle_bms_status_t::Voltage: + datatype = "voltage"; + break; + case vehicle_bms_status_t::Temperature: + datatype = "temperature"; + break; + } + writer->printf("No BMS %s data available\n", datatype); return; } @@ -580,61 +626,133 @@ void OvmsVehicle::BmsStatus(int verbosity, OvmsWriter* writer) case OvmsStatus::Alert: talert++; break; } } + if (show_voltage) + { + writer->puts("Voltage:"); + writer->printf(" Average: %5.3fV [%5.3fV - %5.3fV]\n", + StdMetrics.ms_v_bat_pack_vavg->AsFloat(), + StdMetrics.ms_v_bat_pack_vmin->AsFloat(), + StdMetrics.ms_v_bat_pack_vmax->AsFloat()); + writer->printf(" Deviation: SD %6.2fmV [max %.2fmV], %d warnings, %d alerts\n", + StdMetrics.ms_v_bat_pack_vstddev->AsFloat()*1000, + StdMetrics.ms_v_bat_pack_vstddev_max->AsFloat()*1000, + vwarn, valert); + } - writer->puts("Voltage:"); - writer->printf(" Average: %5.3fV [%5.3fV - %5.3fV]\n", - StdMetrics.ms_v_bat_pack_vavg->AsFloat(), - StdMetrics.ms_v_bat_pack_vmin->AsFloat(), - StdMetrics.ms_v_bat_pack_vmax->AsFloat()); - writer->printf(" Deviation: SD %6.2fmV [max %.2fmV], %d warnings, %d alerts\n", - StdMetrics.ms_v_bat_pack_vstddev->AsFloat()*1000, - StdMetrics.ms_v_bat_pack_vstddev_max->AsFloat()*1000, - vwarn, valert); - - writer->puts("Temperature:"); - writer->printf(" Average: %5.1fC [%5.1fC - %5.1fC]\n", - StdMetrics.ms_v_bat_pack_tavg->AsFloat(), - StdMetrics.ms_v_bat_pack_tmin->AsFloat(), - StdMetrics.ms_v_bat_pack_tmax->AsFloat()); - writer->printf(" Deviation: SD %6.2fC [max %.2fC], %d warnings, %d alerts\n", - StdMetrics.ms_v_bat_pack_tstddev->AsFloat(), - StdMetrics.ms_v_bat_pack_tstddev_max->AsFloat(), - twarn, talert); + if (show_temperature) + { + writer->puts("Temperature:"); + writer->printf(" Average: %5.1fC [%5.1fC - %5.1fC]\n", + StdMetrics.ms_v_bat_pack_tavg->AsFloat(), + StdMetrics.ms_v_bat_pack_tmin->AsFloat(), + StdMetrics.ms_v_bat_pack_tmax->AsFloat()); + writer->printf(" Deviation: SD %6.2fC [max %.2fC], %d warnings, %d alerts\n", + StdMetrics.ms_v_bat_pack_tstddev->AsFloat(), + StdMetrics.ms_v_bat_pack_tstddev_max->AsFloat(), + twarn, talert); + } writer->puts("Cells:"); int kv = 0; int kt = 0; - for (int module = 0; module < ((m_bms_readings_v+m_bms_readingspermodule_v-1)/m_bms_readingspermodule_v); module++) + int module_count = 0; + if (show_voltage) + module_count = round_up_div(m_bms_readings_v,m_bms_readingspermodule_v); + if (show_temperature) + { + int temp_module_count = round_up_div(m_bms_readings_t,m_bms_readingspermodule_t); + if (temp_module_count > module_count) + module_count = temp_module_count; + } + int max_cols_v = 0; + if (show_voltage) + max_cols_v = check_max_cols(m_bms_readingspermodule_v, show_temperature?4:5); + int max_cols_t = 0; + if (show_temperature) + max_cols_t = check_max_cols(m_bms_readingspermodule_t, 5-max_cols_v); + + for (int module = 0; module < module_count; ++module) { writer->printf(" +"); - for (c=0;cprintf("-------"); } - writer->printf("-+"); - for (c=0;cprintf("-------"); } - writer->puts("-+"); - writer->printf("%3d |",module+1); - for (c=0; cprintf(" %5.3fV",m_bms_voltages[kv++]); - else - writer->printf(" "); + for (c=0;cprintf("-------"); } + writer->printf("-+"); } - writer->printf(" |"); - for (c=0; cprintf("-------"); } + writer->printf("-+"); + } + writer->puts(""); + + int rows_v = 0, rows_t = 0; + int reading_left_v = 0, reading_left_t = 0; + if (show_voltage) { - if (kt < m_bms_readings_t) - writer->printf(" %5.1fC",m_bms_temperatures[kt++]); - else - writer->printf(" "); + int items_left_v = m_bms_readings_v - kv; + reading_left_v = std::min(items_left_v, m_bms_readingspermodule_v); + rows_v = round_up_div(reading_left_v, max_cols_v); + } + if (show_temperature) + { + int items_left_t = m_bms_readings_t - kt; + reading_left_t = std::min(items_left_t, m_bms_readingspermodule_t); + rows_t = round_up_div(reading_left_t, max_cols_t); + } + int rows = std::max(rows_v,rows_t); + for (int row = 0 ; row < rows; ++row) + { + if (row == 0) + writer->printf("%3d |",module+1); + else + writer->printf(" |"); + if (show_voltage) + { + for (c=0; c 0)) + { + writer->printf(" %5.3fV",m_bms_voltages[kv]); + --reading_left_v; + ++kv; + } + else + writer->printf(" "); + } + writer->printf(" |"); + } + if (show_temperature) + { + for (c=0; c 0)) + { + writer->printf(" %5.1fC",m_bms_temperatures[kt]); + --reading_left_t; + ++kt; + } + else + writer->printf(" "); + } + writer->printf(" |"); + } + writer->puts(""); } - writer->puts(" |"); } writer->printf(" +"); - for (c=0;cprintf("-------"); } - writer->printf("-+"); - for (c=0;cprintf("-------"); } - writer->puts("-+"); + if (show_voltage) + { + for (c=0;cprintf("-------"); } + writer->printf("-+"); + } + if (show_temperature) + { + for (c=0;cprintf("-------"); } + writer->printf("-+"); + } + writer->puts(""); } bool OvmsVehicle::FormatBmsAlerts(int verbosity, OvmsWriter* writer, bool show_warnings) diff --git a/OVMS.V3/components/vehicle/vehicle_shell.cpp b/OVMS.V3/components/vehicle/vehicle_shell.cpp index b39b6d2..3bf66ee 100644 --- a/OVMS.V3/components/vehicle/vehicle_shell.cpp +++ b/OVMS.V3/components/vehicle/vehicle_shell.cpp @@ -435,7 +435,14 @@ void OvmsVehicleFactory::bms_status(int verbosity, OvmsWriter* writer, OvmsComma { if (MyVehicleFactory.m_currentvehicle != NULL) { - MyVehicleFactory.m_currentvehicle->BmsStatus(verbosity, writer); + OvmsVehicle::vehicle_bms_status_t statusmode = OvmsVehicle::vehicle_bms_status_t::Both; + const char* smode = cmd->GetName(); + if (strcmp(smode,"volt")==0) + statusmode = OvmsVehicle::vehicle_bms_status_t::Voltage; + else if (strcmp(smode,"temp")==0) + statusmode = OvmsVehicle::vehicle_bms_status_t::Temperature; + + MyVehicleFactory.m_currentvehicle->BmsStatus(verbosity, writer, statusmode); } else { diff --git a/OVMS.V3/components/vehicle_renaultzoe_ph2_obd/src/vehicle_renaultzoe_ph2_obd.cpp b/OVMS.V3/components/vehicle_renaultzoe_ph2_obd/src/vehicle_renaultzoe_ph2_obd.cpp index 850e297..6b0de7b 100644 --- a/OVMS.V3/components/vehicle_renaultzoe_ph2_obd/src/vehicle_renaultzoe_ph2_obd.cpp +++ b/OVMS.V3/components/vehicle_renaultzoe_ph2_obd/src/vehicle_renaultzoe_ph2_obd.cpp @@ -87,8 +87,8 @@ OvmsVehicleRenaultZoePh2OBD::OvmsVehicleRenaultZoePh2OBD() { mt_inv_hv_current = MyMetrics.InitFloat("zph2.i.current", SM_STALE_MID, 0, Amps); mt_mot_temp_stator1 = MyMetrics.InitFloat("zph2.m.temp.stator1", SM_STALE_MID, 0, Celcius); mt_mot_temp_stator2 = MyMetrics.InitFloat("zph2.m.temp.stator2", SM_STALE_MID, 0, Celcius); - mt_hvac_compressor_speed = MyMetrics.InitFloat("zph2.h.compressor.speed", SM_STALE_MID, 0, rpm); - mt_hvac_compressor_pressure = MyMetrics.InitFloat("zph2.h.compressor.pressure", SM_STALE_MID, 0, Bar); + mt_hvac_compressor_speed = MyMetrics.InitFloat("zph2.h.compressor.speed", SM_STALE_MID, 0); + mt_hvac_compressor_pressure = MyMetrics.InitFloat("zph2.h.compressor.pressure", SM_STALE_MID, 0); mt_hvac_compressor_power = MyMetrics.InitFloat("zph2.h.compressor.power", SM_STALE_MID, 0, Watts); mt_hvac_compressor_mode = MyMetrics.InitString("zph2.h.compressor.mode", SM_STALE_MID, 0, Other);