Compare commits
132 commits
3.3.002-cs
...
master
Author | SHA1 | Date | |
---|---|---|---|
Carsten Schmiemann | d5c089feb0 | ||
Carsten Schmiemann | 1b7124c2c7 | ||
Carsten Schmiemann | 9eb77d6aef | ||
Carsten Schmiemann | 5c2f3497db | ||
Carsten Schmiemann | 69b4d25e62 | ||
Carsten Schmiemann | f0aa4187c7 | ||
Carsten Schmiemann | c1a2b4dbf8 | ||
Carsten Schmiemann | 34ad8c41b8 | ||
Carsten Schmiemann | 5d5d8b7870 | ||
Carsten Schmiemann | b4486dd06e | ||
Carsten Schmiemann | a3bb202c6a | ||
Carsten Schmiemann | 705a4d1d3a | ||
Carsten Schmiemann | 6c8ca654bc | ||
Carsten Schmiemann | 0db69f901c | ||
Carsten Schmiemann | 3d87aa9a79 | ||
Carsten Schmiemann | 9a451be72a | ||
Carsten Schmiemann | 9c874adfaa | ||
Carsten Schmiemann | fe485dc049 | ||
Carsten Schmiemann | 5b036b9ba6 | ||
Carsten Schmiemann | 08269a30c3 | ||
Carsten Schmiemann | 42e5f1c6ba | ||
Carsten Schmiemann | 5bf9c60a47 | ||
Carsten Schmiemann | 89d64b2211 | ||
Carsten Schmiemann | 848429860c | ||
Carsten Schmiemann | 901371a989 | ||
Carsten Schmiemann | c761ec774c | ||
Carsten Schmiemann | 3121178a97 | ||
Carsten Schmiemann | 88661c680d | ||
Carsten Schmiemann | 949affec1f | ||
Carsten Schmiemann | 8bbf09ffc5 | ||
Carsten Schmiemann | cf9242d798 | ||
Carsten Schmiemann | 54ab5fa818 | ||
Carsten Schmiemann | ba1a0b10a3 | ||
Carsten Schmiemann | ef2f091267 | ||
Carsten Schmiemann | 631d3bbb2c | ||
Carsten Schmiemann | 1bbb754ff7 | ||
Carsten Schmiemann | 54edebfb5b | ||
Carsten Schmiemann | d7944c8894 | ||
Carsten Schmiemann | 337b736771 | ||
Carsten Schmiemann | f6f72e8c16 | ||
Carsten Schmiemann | 58402124dd | ||
Carsten Schmiemann | 5d3e4f4efa | ||
Carsten Schmiemann | fa09dc8c71 | ||
Carsten Schmiemann | 57e0666b47 | ||
Carsten Schmiemann | a95e6e4fa2 | ||
Carsten Schmiemann | dab42140b8 | ||
Carsten Schmiemann | 2f9e12f0f0 | ||
Carsten Schmiemann | a2a079c812 | ||
Carsten Schmiemann | e6f2a6b992 | ||
Carsten Schmiemann | b5e18a4c0f | ||
Carsten Schmiemann | de5abbbace | ||
Carsten Schmiemann | 70575cd193 | ||
Carsten Schmiemann | ba5aa7d84c | ||
Carsten Schmiemann | 5955b23617 | ||
Carsten Schmiemann | 3433335cbe | ||
Carsten Schmiemann | 4a298c2d21 | ||
Carsten Schmiemann | 96ffaf8f40 | ||
Carsten Schmiemann | faad212a43 | ||
Carsten Schmiemann | 1fa378c5f9 | ||
Carsten Schmiemann | 7ea81e8fa4 | ||
Carsten Schmiemann | a0ec7148db | ||
Carsten Schmiemann | b17eca6d14 | ||
Carsten Schmiemann | 6faf2aee97 | ||
Carsten Schmiemann | 4063e7167c | ||
Carsten Schmiemann | 259d13b3f1 | ||
Carsten Schmiemann | 15e8d58744 | ||
Carsten Schmiemann | 798acb1839 | ||
Carsten Schmiemann | b36c0c4621 | ||
Carsten Schmiemann | 6d07e8fe64 | ||
Carsten Schmiemann | 8f285cc917 | ||
Carsten Schmiemann | 894a063083 | ||
Carsten Schmiemann | dec6c220d5 | ||
Carsten Schmiemann | c83a176527 | ||
Carsten Schmiemann | 2b6285307e | ||
Carsten Schmiemann | d9d0e00435 | ||
Carsten Schmiemann | a782c48079 | ||
Carsten Schmiemann | 81fb803667 | ||
Carsten Schmiemann | e5c13e0bb6 | ||
Carsten Schmiemann | c3cd9ba23e | ||
Carsten Schmiemann | ad786045ae | ||
Carsten Schmiemann | eeb4e06e04 | ||
Carsten Schmiemann | 9e7939b514 | ||
Carsten Schmiemann | 9ceead8a77 | ||
Carsten Schmiemann | c1f026933c | ||
Carsten Schmiemann | e1d8a850b1 | ||
Carsten Schmiemann | cd469ff48a | ||
Carsten Schmiemann | cd537f1907 | ||
Carsten Schmiemann | 34fe261ec9 | ||
Carsten Schmiemann | 3ea43525b2 | ||
Carsten Schmiemann | 59d452452e | ||
Carsten Schmiemann | e0d0968211 | ||
Carsten Schmiemann | c7758be02b | ||
Carsten Schmiemann | afc7fb8b2b | ||
Carsten Schmiemann | 6e6df5fa01 | ||
Carsten Schmiemann | 105cf60e3c | ||
Carsten Schmiemann | 011cc31d50 | ||
Carsten Schmiemann | c6858eaf16 | ||
Carsten Schmiemann | 43df545b41 | ||
Carsten Schmiemann | 1edbfcb331 | ||
Carsten Schmiemann | ee2435006e | ||
Carsten Schmiemann | e1c8c563c4 | ||
Carsten Schmiemann | 88130b05bc | ||
Carsten Schmiemann | b30cd3498f | ||
Carsten Schmiemann | 40952e9730 | ||
Carsten Schmiemann | d0b1911f3b | ||
Carsten Schmiemann | ac6471ad99 | ||
Carsten Schmiemann | 7614b6809b | ||
Carsten Schmiemann | dcf134ba2e | ||
Carsten Schmiemann | df8ffc1bc5 | ||
Carsten Schmiemann | bb58a0cb9f | ||
Carsten Schmiemann | 76e9d97385 | ||
Carsten Schmiemann | 32f6b2560d | ||
Carsten Schmiemann | ea0fd89c56 | ||
Carsten Schmiemann | e0107bee1c | ||
Carsten Schmiemann | 36f7e1aff2 | ||
Carsten Schmiemann | c4ed87552c | ||
Carsten Schmiemann | 150338320b | ||
Carsten Schmiemann | c0896e209a | ||
Carsten Schmiemann | 424cc5c24f | ||
Carsten Schmiemann | 29f880300c | ||
Carsten Schmiemann | 0bf1180a48 | ||
Carsten Schmiemann | 0321a36088 | ||
Carsten Schmiemann | 910f480a9b | ||
Carsten Schmiemann | 4d79bbdf7b | ||
Carsten Schmiemann | 781be6126d | ||
Carsten Schmiemann | 84293ed725 | ||
Carsten Schmiemann | efb2404917 | ||
Carsten Schmiemann | aac0445c26 | ||
Carsten Schmiemann | cf7dbe93dc | ||
Carsten Schmiemann | 69a64bc1f1 | ||
Carsten Schmiemann | de9389dab3 | ||
Carsten Schmiemann | 6ca15dca10 |
|
@ -1 +1 @@
|
|||
Subproject commit 1ff5e24b1b722a225e904b0d1b505d8a7c6b10be
|
||||
Subproject commit 25d79ca572cf6b92ead9fa45a9cb9579cb0bd092
|
|
@ -213,7 +213,7 @@ void can_tx(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const
|
|||
uint32_t uv = strtoul(argv[0], &ep, 16);
|
||||
if (*ep != '\0' || uv > idmax)
|
||||
{
|
||||
writer->printf("Error: Invalid CAN ID \"%s\" (0x%lx max)\n", argv[0], idmax);
|
||||
writer->printf("Error: Invalid CAN ID \"%s\" (0x%x max)\n", argv[0], idmax);
|
||||
return;
|
||||
}
|
||||
frame.MsgID = uv;
|
||||
|
@ -298,7 +298,7 @@ void can_testtx(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, c
|
|||
uint32_t uv = strtoul(argv[0], &ep, 16);
|
||||
if (*ep != '\0' || uv > idmax)
|
||||
{
|
||||
writer->printf("Error: Invalid CAN ID \"%s\" (0x%lx max)\n", argv[0], idmax);
|
||||
writer->printf("Error: Invalid CAN ID \"%s\" (0x%x max)\n", argv[0], idmax);
|
||||
return;
|
||||
}
|
||||
frame.MsgID = uv;
|
||||
|
@ -570,7 +570,8 @@ static const char* const CAN_log_type_names[] = {
|
|||
"Status",
|
||||
"Comment",
|
||||
"Info",
|
||||
"Event"
|
||||
"Event",
|
||||
"Metric"
|
||||
};
|
||||
|
||||
const char* GetCanLogTypeName(CAN_log_type_t type)
|
||||
|
|
|
@ -251,6 +251,7 @@ typedef enum
|
|||
CAN_LogInfo_Comment, // general comment
|
||||
CAN_LogInfo_Config, // logger setup info (type, file, filters, vehicle)
|
||||
CAN_LogInfo_Event, // system event (i.e. vehicle started)
|
||||
CAN_LogInfo_Metric, // system or plugin metric (i.e. v.p.altitude)
|
||||
} CAN_log_type_t;
|
||||
|
||||
// Log message:
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
*/
|
||||
|
||||
#include "ovms_log.h"
|
||||
static const char *TAG = "canformat-crtd";
|
||||
static const char *TAG = "canformat-cs11";
|
||||
|
||||
#include <errno.h>
|
||||
#include "pcp.h"
|
||||
|
|
|
@ -123,10 +123,11 @@ std::string canformat_crtd::get(CAN_log_message_t* message)
|
|||
case CAN_LogInfo_Comment:
|
||||
case CAN_LogInfo_Config:
|
||||
case CAN_LogInfo_Event:
|
||||
case CAN_LogInfo_Metric:
|
||||
snprintf(buf,sizeof(buf),"%ld.%06ld %c%s %s %s",
|
||||
message->timestamp.tv_sec, message->timestamp.tv_usec,
|
||||
busnumber,
|
||||
(message->type == CAN_LogInfo_Event) ? "CEV" : "CXX",
|
||||
(message->type == CAN_LogInfo_Event) ? "CEV" : (message->type == CAN_LogInfo_Metric) ? "CMT" : "CXX",
|
||||
GetCanLogTypeName(message->type),
|
||||
message->text);
|
||||
break;
|
||||
|
@ -151,7 +152,7 @@ std::string canformat_crtd::getheader(struct timeval *time)
|
|||
time = &t;
|
||||
}
|
||||
|
||||
snprintf(buf,sizeof(buf),"%ld.%06ld CXX OVMS CRTD\n%ld.%06ld CVR 3.0\n",
|
||||
snprintf(buf,sizeof(buf),"%ld.%06ld CXX OVMS CRTD\n%ld.%06ld CVR 3.1\n",
|
||||
time->tv_sec, time->tv_usec,
|
||||
time->tv_sec, time->tv_usec);
|
||||
|
||||
|
|
|
@ -25,44 +25,44 @@
|
|||
*/
|
||||
|
||||
#include "ovms_log.h"
|
||||
static const char *TAG = "canformat-lawricel";
|
||||
static const char *TAG = "canformat-lawicel";
|
||||
|
||||
#include <errno.h>
|
||||
#include "pcp.h"
|
||||
#include "canformat_lawricel.h"
|
||||
#include "canformat_lawicel.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Initialisation and Registration
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class OvmsCanFormatLawricelInit
|
||||
class OvmsCanFormatLawicelInit
|
||||
{
|
||||
public: OvmsCanFormatLawricelInit();
|
||||
} MyOvmsCanFormatLawricelTInit __attribute__ ((init_priority (4505)));
|
||||
public: OvmsCanFormatLawicelInit();
|
||||
} MyOvmsCanFormatLawicelTInit __attribute__ ((init_priority (4505)));
|
||||
|
||||
OvmsCanFormatLawricelInit::OvmsCanFormatLawricelInit()
|
||||
OvmsCanFormatLawicelInit::OvmsCanFormatLawicelInit()
|
||||
{
|
||||
ESP_LOGI(TAG, "Registering CAN Format: LAWRICEL (4505)");
|
||||
ESP_LOGI(TAG, "Registering CAN Format: LAWICEL (4505)");
|
||||
|
||||
MyCanFormatFactory.RegisterCanFormat<canformat_lawricel>("lawricel");
|
||||
MyCanFormatFactory.RegisterCanFormat<canformat_lawicel>("lawicel");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Base GVRET implementation (utility)
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
canformat_lawricel::canformat_lawricel(const char* type)
|
||||
canformat_lawicel::canformat_lawicel(const char* type)
|
||||
: canformat(type)
|
||||
{
|
||||
}
|
||||
|
||||
canformat_lawricel::~canformat_lawricel()
|
||||
canformat_lawicel::~canformat_lawicel()
|
||||
{
|
||||
}
|
||||
|
||||
std::string canformat_lawricel::get(CAN_log_message_t* message)
|
||||
std::string canformat_lawicel::get(CAN_log_message_t* message)
|
||||
{
|
||||
char buf[CANFORMAT_LAWRICEL_MAXLEN];
|
||||
char buf[CANFORMAT_LAWICEL_MAXLEN];
|
||||
|
||||
if ((message->type != CAN_LogFrame_RX)&&
|
||||
(message->type != CAN_LogFrame_TX))
|
||||
|
@ -87,12 +87,12 @@ std::string canformat_lawricel::get(CAN_log_message_t* message)
|
|||
return std::string(buf);
|
||||
}
|
||||
|
||||
std::string canformat_lawricel::getheader(struct timeval *time)
|
||||
std::string canformat_lawicel::getheader(struct timeval *time)
|
||||
{
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
size_t canformat_lawricel::put(CAN_log_message_t* message, uint8_t *buffer, size_t len, bool* hasmore, canlogconnection* clc)
|
||||
size_t canformat_lawicel::put(CAN_log_message_t* message, uint8_t *buffer, size_t len, bool* hasmore, canlogconnection* clc)
|
||||
{
|
||||
if (m_buf.FreeSpace()==0) SetServeDiscarding(true); // Buffer full, so discard from now on
|
||||
if (IsServeDiscarding()) return len; // Quick return if discarding
|
|
@ -24,18 +24,18 @@
|
|||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __CANFORMAT_LAWRICEL_H__
|
||||
#define __CANFORMAT_LAWRICEL_H__
|
||||
#ifndef __CANFORMAT_LAWICEL_H__
|
||||
#define __CANFORMAT_LAWICEL_H__
|
||||
|
||||
#include "canformat.h"
|
||||
|
||||
#define CANFORMAT_LAWRICEL_MAXLEN 48
|
||||
#define CANFORMAT_LAWICEL_MAXLEN 48
|
||||
|
||||
class canformat_lawricel : public canformat
|
||||
class canformat_lawicel : public canformat
|
||||
{
|
||||
public:
|
||||
canformat_lawricel(const char* type);
|
||||
virtual ~canformat_lawricel();
|
||||
canformat_lawicel(const char* type);
|
||||
virtual ~canformat_lawicel();
|
||||
|
||||
public:
|
||||
virtual std::string get(CAN_log_message_t* message);
|
||||
|
@ -43,4 +43,4 @@ class canformat_lawricel : public canformat
|
|||
virtual size_t put(CAN_log_message_t* message, uint8_t *buffer, size_t len, bool* hasmore, canlogconnection* clc=NULL);
|
||||
};
|
||||
|
||||
#endif // __CANFORMAT_LAWRICEL_H__
|
||||
#endif // __CANFORMAT_LAWICEL_H__
|
88
OVMS.V3/components/can/src/canformat_panda.cpp
Normal file
88
OVMS.V3/components/can/src/canformat_panda.cpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Module: CAN dump framework
|
||||
; Date: 18th January 2018
|
||||
;
|
||||
; (C) 2022 Mark Webb-Johnson
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ovms_log.h"
|
||||
static const char *TAG = "canformat-panda";
|
||||
|
||||
#include <errno.h>
|
||||
#include "pcp.h"
|
||||
#include "canlog.h"
|
||||
#include "canformat_panda.h"
|
||||
#include "ovms_utils.h"
|
||||
|
||||
class OvmsCanFormatPandaInit
|
||||
{
|
||||
public: OvmsCanFormatPandaInit();
|
||||
} MyOvmsCanFormatPandaInit __attribute__ ((init_priority (4505)));
|
||||
|
||||
OvmsCanFormatPandaInit::OvmsCanFormatPandaInit()
|
||||
{
|
||||
ESP_LOGI(TAG, "Registering CAN Format: PANDA (4505)");
|
||||
|
||||
MyCanFormatFactory.RegisterCanFormat<canformat_panda>("panda");
|
||||
}
|
||||
|
||||
canformat_panda::canformat_panda(const char *type)
|
||||
: canformat(type)
|
||||
{
|
||||
}
|
||||
|
||||
canformat_panda::~canformat_panda()
|
||||
{
|
||||
}
|
||||
|
||||
std::string canformat_panda::get(CAN_log_message_t* message)
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t w1;
|
||||
uint32_t w2;
|
||||
uint64_t data;
|
||||
} packet;
|
||||
|
||||
switch (message->type)
|
||||
{
|
||||
case CAN_LogFrame_RX:
|
||||
case CAN_LogFrame_TX:
|
||||
packet.w1 = (uint32_t)message->frame.MsgID <<21;
|
||||
packet.w2 = (message->frame.FIR.B.DLC & 0x0f) | (message->origin->m_busnumber << 4);
|
||||
memcpy(&packet.data, message->frame.data.u8, 8);
|
||||
return std::string((char*)&packet,sizeof(packet));
|
||||
|
||||
default:
|
||||
return std::string("");
|
||||
}
|
||||
}
|
||||
|
||||
std::string canformat_panda::getheader(struct timeval *time)
|
||||
{
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
size_t canformat_panda::put(CAN_log_message_t* message, uint8_t *buffer, size_t len, bool* hasmore, canlogconnection* clc)
|
||||
{
|
||||
return len; // Just ignore incoming data
|
||||
}
|
44
OVMS.V3/components/can/src/canformat_panda.h
Normal file
44
OVMS.V3/components/can/src/canformat_panda.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Module: CAN dump CRTD format
|
||||
; Date: 18th January 2018
|
||||
;
|
||||
; (C) 2022 Mark Webb-Johnson
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __CANFORMAT_PANDA_H__
|
||||
#define __CANFORMAT_PANDA_H__
|
||||
|
||||
#include "canformat.h"
|
||||
|
||||
class canformat_panda : public canformat
|
||||
{
|
||||
public:
|
||||
canformat_panda(const char* type);
|
||||
virtual ~canformat_panda();
|
||||
|
||||
public:
|
||||
virtual std::string get(CAN_log_message_t* message);
|
||||
virtual std::string getheader(struct timeval *time);
|
||||
virtual size_t put(CAN_log_message_t* message, uint8_t *buffer, size_t len, bool* hasmore, canlogconnection* clc=NULL);
|
||||
};
|
||||
|
||||
#endif // __CANFORMAT_PANDA_H__
|
|
@ -42,6 +42,8 @@ static const char *TAG = "canlog";
|
|||
#include "ovms_peripherals.h"
|
||||
#include "metrics_standard.h"
|
||||
|
||||
static const char *CAN_PARAM = "can";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Command Processing
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -352,8 +354,12 @@ canlog::canlog(const char* type, std::string format, canformat::canformat_serve_
|
|||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
MyEvents.RegisterEvent(IDTAG, "*", std::bind(&canlog::EventListener, this, _1, _2));
|
||||
MyEvents.RegisterEvent(IDTAG,"config.mounted", std::bind(&canlog::UpdatedConfig, this, _1, _2));
|
||||
MyEvents.RegisterEvent(IDTAG,"config.changed", std::bind(&canlog::UpdatedConfig, this, _1, _2));
|
||||
MyMetrics.RegisterListener(IDTAG, "*", std::bind(&canlog::MetricListener, this, _1));
|
||||
|
||||
int queuesize = MyConfig.GetParamValueInt("can", "log.queuesize",100);
|
||||
int queuesize = MyConfig.GetParamValueInt(CAN_PARAM, "log.queuesize",100);
|
||||
LoadConfig();
|
||||
m_queue = xQueueCreate(queuesize, sizeof(CAN_log_message_t));
|
||||
xTaskCreatePinnedToCore(RxTask, "OVMS CanLog", 4096, (void*)this, 10, &m_task, CORE(1));
|
||||
}
|
||||
|
@ -361,6 +367,7 @@ canlog::canlog(const char* type, std::string format, canformat::canformat_serve_
|
|||
canlog::~canlog()
|
||||
{
|
||||
MyEvents.DeregisterEvent(IDTAG);
|
||||
MyMetrics.DeregisterListener(IDTAG);
|
||||
|
||||
if (m_task)
|
||||
{
|
||||
|
@ -383,6 +390,7 @@ canlog::~canlog()
|
|||
case CAN_LogInfo_Comment:
|
||||
case CAN_LogInfo_Config:
|
||||
case CAN_LogInfo_Event:
|
||||
case CAN_LogInfo_Metric:
|
||||
free(msg.text);
|
||||
break;
|
||||
default:
|
||||
|
@ -418,6 +426,7 @@ void canlog::RxTask(void *context)
|
|||
case CAN_LogInfo_Comment:
|
||||
case CAN_LogInfo_Config:
|
||||
case CAN_LogInfo_Event:
|
||||
case CAN_LogInfo_Metric:
|
||||
me->OutputMsg(msg);
|
||||
free(msg.text);
|
||||
break;
|
||||
|
@ -429,13 +438,179 @@ void canlog::RxTask(void *context)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a comma-separated list of filters, and assign them to a member of the class.
|
||||
* We have 3 kind of comparisons, and an unlimited list of filters.
|
||||
*
|
||||
* A filter can be:
|
||||
* - A "startsWith" comparison - when ending with '*',
|
||||
* - An "endsWith" comparison - when starting with '*',
|
||||
* - Invalid (and skipped) if empty, or with a '*' in any other position than beginning or end,
|
||||
* - A "string equal" comparison for all other cases
|
||||
*/
|
||||
static void LoadFilters(conn_filters_arr_t &member, const std::string &value)
|
||||
{
|
||||
// Empty all previously defined filters, for all operators
|
||||
for (int i=0; i<COUNT_OF_OPERATORS; i++)
|
||||
{
|
||||
member[i].clear();
|
||||
}
|
||||
|
||||
if (!value.empty())
|
||||
{
|
||||
std::stringstream stream (value);
|
||||
std::string item;
|
||||
unsigned char comparison_operator;
|
||||
|
||||
// Comma-separated list
|
||||
while (getline (stream, item, ','))
|
||||
{
|
||||
trim(item); // Removing leading and trailing spaces
|
||||
|
||||
if (item.empty())
|
||||
{
|
||||
ESP_LOGW(TAG, "LoadFilters: skipping empty value in the filter list");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if there is a wildcard ('*') in any other place than first or last position
|
||||
size_t wildcard_position = item.find('*', 1);
|
||||
if ((wildcard_position != std::string::npos) && (wildcard_position != item.size()-1))
|
||||
{
|
||||
ESP_LOGW(TAG, "LoadFilters: skipping incorrect value (%s) in the filter list (wildcard in wrong position)", item.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Depending on the presence and position of the wildcard, push the filter
|
||||
// in the proper vector (without the wildcard)
|
||||
if (item.front() == '*')
|
||||
{
|
||||
comparison_operator = OPERATOR_ENDSWITH;
|
||||
item.erase(0, 1);
|
||||
}
|
||||
else if (item.back() == '*')
|
||||
{
|
||||
comparison_operator = OPERATOR_STARTSWITH;
|
||||
item.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
comparison_operator = OPERATOR_EQUALS;
|
||||
}
|
||||
member[comparison_operator].push_back(item);
|
||||
}
|
||||
}
|
||||
|
||||
// for (int i=0; i<COUNT_OF_OPERATORS; i++)
|
||||
// {
|
||||
// ESP_LOGI(TAG, "LoadFilters: filters for operator %d:", i);
|
||||
// for (std::vector<std::string>::iterator it=member[i].begin(); it!=member[i].end(); ++it)
|
||||
// {
|
||||
// ESP_LOGI(TAG, "LoadFilters: filter value '%s'", it->c_str());
|
||||
// }
|
||||
// if (member[i].begin() == member[i].end())
|
||||
// {
|
||||
// ESP_LOGI(TAG, "LoadFilters: (empty filter list)");
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Load, or reload, the configuration of events and metrics filters.
|
||||
*
|
||||
* The configuration item is a string containing a comma-separated list of filters.
|
||||
*/
|
||||
void canlog::LoadConfig()
|
||||
{
|
||||
std::size_t str_hash;
|
||||
|
||||
std::string list_of_events_filters = MyConfig.GetParamValue(CAN_PARAM, "log.events_filters", "x*,vehicle*");
|
||||
str_hash = std::hash<std::string>{}(list_of_events_filters);
|
||||
if (str_hash != m_events_filters_hash)
|
||||
{
|
||||
m_events_filters_hash = str_hash;
|
||||
LoadFilters(m_events_filters, list_of_events_filters);
|
||||
MyCan.LogInfo(NULL, CAN_LogInfo_Config, ("Events filters: " + list_of_events_filters).c_str());
|
||||
}
|
||||
std::string list_of_metrics_filters = MyConfig.GetParamValue(CAN_PARAM, "log.metrics_filters");
|
||||
str_hash = std::hash<std::string>{}(list_of_metrics_filters);
|
||||
if (str_hash != m_metrics_filters_hash)
|
||||
{
|
||||
m_metrics_filters_hash = str_hash;
|
||||
LoadFilters(m_metrics_filters, list_of_metrics_filters);
|
||||
MyCan.LogInfo(NULL, CAN_LogInfo_Config, ("Metrics filters: " + list_of_metrics_filters).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load, or reload, the configuration if a config event occurred.
|
||||
*/
|
||||
void canlog::UpdatedConfig(std::string event, void* data)
|
||||
{
|
||||
if (event == "config.changed")
|
||||
{
|
||||
// Only reload if our parameter has changed
|
||||
OvmsConfigParam*p = (OvmsConfigParam*)data;
|
||||
if (p->GetName() != CAN_PARAM)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
LoadConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a value matches in a list of filters.
|
||||
*
|
||||
* Match can be a:
|
||||
* - startsWith match,
|
||||
* - endsWith match,
|
||||
* - equality match.
|
||||
*/
|
||||
static bool CheckFilter(conn_filters_arr_t &member, const std::string &value)
|
||||
{
|
||||
for (int i=0; i<COUNT_OF_OPERATORS; i++)
|
||||
{
|
||||
for (std::vector<std::string>::iterator it=member[i].begin(); it!=member[i].end(); ++it)
|
||||
{
|
||||
if ((i == OPERATOR_STARTSWITH) && (startsWith(value, *it)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ((i == OPERATOR_ENDSWITH) && (endsWith(value, *it)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if ((i == OPERATOR_EQUALS) && (value == *it))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void canlog::EventListener(std::string event, void* data)
|
||||
{
|
||||
// Log vehicle custom (x…) & framework events:
|
||||
if (startsWith(event, 'x') || startsWith(event, "vehicle"))
|
||||
if (CheckFilter(m_events_filters, event))
|
||||
LogInfo(NULL, CAN_LogInfo_Event, event.c_str());
|
||||
}
|
||||
|
||||
void canlog::MetricListener(OvmsMetric* metric)
|
||||
{
|
||||
std::string name = metric->m_name;
|
||||
// Log metrics (in JSON for later parsing):
|
||||
if (CheckFilter(m_metrics_filters, name))
|
||||
{
|
||||
std::string metric_text = "{ ";
|
||||
metric_text += "\"name\": \"" + json_encode(name) + "\", ";
|
||||
metric_text += "\"value\": " + metric->AsJSON() + ", ";
|
||||
metric_text += "\"unit\": \"" + json_encode(std::string(OvmsMetricUnitLabel(metric->GetUnits()))) + "\" }";
|
||||
LogInfo(NULL, CAN_LogInfo_Metric, metric_text.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
const char* canlog::GetType()
|
||||
{
|
||||
return m_type;
|
||||
|
@ -596,7 +771,11 @@ void canlog::LogInfo(canbus* bus, CAN_log_type_t type, const char* text)
|
|||
msg.origin = bus;
|
||||
msg.text = strdup(text);
|
||||
m_msgcount++;
|
||||
if (xQueueSend(m_queue, &msg, 0) != pdTRUE) m_dropcount++;
|
||||
if (xQueueSend(m_queue, &msg, 0) != pdTRUE)
|
||||
{
|
||||
m_dropcount++;
|
||||
free(msg.text);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -95,6 +95,11 @@ class canlogconnection: public InternalRamAllocated
|
|||
uint32_t m_filtercount;
|
||||
};
|
||||
|
||||
#define OPERATOR_STARTSWITH 0
|
||||
#define OPERATOR_ENDSWITH 1
|
||||
#define OPERATOR_EQUALS 2
|
||||
#define COUNT_OF_OPERATORS 3
|
||||
typedef std::array<std::vector<std::string>, COUNT_OF_OPERATORS> conn_filters_arr_t;
|
||||
|
||||
class canlog : public InternalRamAllocated
|
||||
{
|
||||
|
@ -105,6 +110,7 @@ class canlog : public InternalRamAllocated
|
|||
public:
|
||||
static void RxTask(void* context);
|
||||
void EventListener(std::string event, void* data);
|
||||
void MetricListener(OvmsMetric* metric);
|
||||
|
||||
public:
|
||||
const char* GetType();
|
||||
|
@ -152,6 +158,16 @@ class canlog : public InternalRamAllocated
|
|||
uint32_t m_msgcount;
|
||||
uint32_t m_dropcount;
|
||||
uint32_t m_filtercount;
|
||||
|
||||
protected:
|
||||
virtual void UpdatedConfig(std::string event, void* data);
|
||||
virtual void LoadConfig();
|
||||
|
||||
protected:
|
||||
conn_filters_arr_t m_events_filters;
|
||||
size_t m_events_filters_hash = 0;
|
||||
conn_filters_arr_t m_metrics_filters;
|
||||
size_t m_metrics_filters_hash = 0;
|
||||
};
|
||||
|
||||
#endif // __CANLOG_H__
|
||||
|
|
|
@ -109,6 +109,7 @@ void canlog_monitor_conn::OutputMsg(CAN_log_message_t& msg, std::string &result)
|
|||
case CAN_LogInfo_Comment:
|
||||
case CAN_LogInfo_Config:
|
||||
case CAN_LogInfo_Event:
|
||||
case CAN_LogInfo_Metric:
|
||||
ESP_LOGD(TAG,"%s",result.c_str());
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -34,7 +34,6 @@ static const char *TAG = "canlog-tcpclient";
|
|||
#include "canformat.h"
|
||||
#include "canlog_tcpclient.h"
|
||||
#include "ovms_config.h"
|
||||
#include "ovms_peripherals.h"
|
||||
|
||||
canlog_tcpclient* MyCanLogTcpClient = NULL;
|
||||
|
||||
|
@ -83,9 +82,9 @@ OvmsCanLogTcpClientInit::OvmsCanLogTcpClientInit()
|
|||
{
|
||||
// We have a place to put our command tree..
|
||||
OvmsCommand* start = cmd_can_log_start->RegisterCommand("tcpclient", "CAN logging as TCP client");
|
||||
OvmsCommand* discard = start->RegisterCommand("discard","CAN logging as TCP client (discard mode)");
|
||||
OvmsCommand* simulate = start->RegisterCommand("simulate","CAN logging as TCP client (simulate mode)");
|
||||
OvmsCommand* transmit = start->RegisterCommand("transmit","CAN logging as TCP client (transmit mode)");
|
||||
OvmsCommand* discard = start->RegisterCommand("discard", "CAN logging as TCP client (discard mode)");
|
||||
OvmsCommand* simulate = start->RegisterCommand("simulate", "CAN logging as TCP client (simulate mode)");
|
||||
OvmsCommand* transmit = start->RegisterCommand("transmit", "CAN logging as TCP client (transmit mode)");
|
||||
MyCanFormatFactory.RegisterCommandSet(discard, "Start CAN logging as TCP client (discard mode)",
|
||||
can_log_tcpclient_start,
|
||||
"<host:port> [filter1] ... [filterN]\n"
|
||||
|
@ -164,23 +163,25 @@ bool canlog_tcpclient::Open()
|
|||
opts.error_string = &err;
|
||||
if (mg_connect_opt(mgr, m_path.c_str(), tcMongooseHandler, opts) != NULL)
|
||||
{
|
||||
return true;
|
||||
// Wait 10s max for connection establishment...
|
||||
m_connecting.Take(pdMS_TO_TICKS(10*1000));
|
||||
return m_isopen;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG,"Could not connect to %s",m_path.c_str());
|
||||
ESP_LOGE(TAG, "Could not connect to %s", m_path.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG,"Delay TCP client (as network manager not up)");
|
||||
ESP_LOGI(TAG, "Delay TCP client (as network manager not up)");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG,"Network manager is not available");
|
||||
ESP_LOGE(TAG, "Network manager is not available");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -221,9 +222,9 @@ void canlog_tcpclient::MongooseHandler(struct mg_connection *nc, int ev, void *p
|
|||
int *success = (int*)p;
|
||||
ESP_LOGV(TAG, "MongooseHandler(MG_EV_CONNECT=%d)",*success);
|
||||
if (*success == 0)
|
||||
{ // Successful connection
|
||||
{ // Connection successful
|
||||
OvmsRecMutexLock lock(&m_cmmutex);
|
||||
ESP_LOGI(TAG, "Connection successful to %s",m_path.c_str());
|
||||
ESP_LOGI(TAG, "Connection successful to %s", m_path.c_str());
|
||||
canlogconnection* clc = new canlogconnection(this, m_format, m_mode);
|
||||
clc->m_nc = nc;
|
||||
clc->m_peer = m_path;
|
||||
|
@ -236,11 +237,11 @@ void canlog_tcpclient::MongooseHandler(struct mg_connection *nc, int ev, void *p
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Connection failed
|
||||
ESP_LOGE(TAG, "Connection failed to %s",m_path.c_str());
|
||||
{ // Connection failed
|
||||
ESP_LOGE(TAG, "Connection failed to %s", m_path.c_str());
|
||||
m_isopen = false;
|
||||
}
|
||||
m_connecting.Give();
|
||||
}
|
||||
break;
|
||||
case MG_EV_CLOSE:
|
||||
|
@ -248,7 +249,7 @@ void canlog_tcpclient::MongooseHandler(struct mg_connection *nc, int ev, void *p
|
|||
if (m_isopen)
|
||||
{
|
||||
OvmsRecMutexLock lock(&m_cmmutex);
|
||||
ESP_LOGE(TAG,"Disconnected from %s",m_path.c_str());
|
||||
ESP_LOGE(TAG, "Disconnected from %s", m_path.c_str());
|
||||
m_isopen = false;
|
||||
auto k = m_connmap.find(nc);
|
||||
if (k != m_connmap.end())
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "canlog.h"
|
||||
#include "ovms_netmanager.h"
|
||||
#include "ovms_mutex.h"
|
||||
#include "ovms_semaphore.h"
|
||||
|
||||
class canlog_tcpclient : public canlog
|
||||
{
|
||||
|
@ -48,6 +49,7 @@ class canlog_tcpclient : public canlog
|
|||
|
||||
public:
|
||||
std::string m_path;
|
||||
OvmsSemaphore m_connecting;
|
||||
};
|
||||
|
||||
#endif // __CANLOG_TCP_CLIENT_H__
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#ifdef CONFIG_OVMS_SC_GPL_MONGOOSE
|
||||
|
||||
#include "canlog.h"
|
||||
#include "canlog_tcpserver.h"
|
||||
#include "ovms_netmanager.h"
|
||||
#include "ovms_mutex.h"
|
||||
|
||||
|
|
330
OVMS.V3/components/can/src/canlog_udpserver.cpp
Normal file
330
OVMS.V3/components/can/src/canlog_udpserver.cpp
Normal file
|
@ -0,0 +1,330 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Module: CAN logging framework
|
||||
; Date: 18th January 2018
|
||||
;
|
||||
; (C) 2018 Michael Balzer
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sdkconfig.h>
|
||||
#ifdef CONFIG_OVMS_SC_GPL_MONGOOSE
|
||||
|
||||
#include "ovms_log.h"
|
||||
static const char *TAG = "canlog-udpserver";
|
||||
|
||||
#include "can.h"
|
||||
#include "canformat.h"
|
||||
#include "canlog_udpserver.h"
|
||||
#include "ovms_config.h"
|
||||
#include "ovms_events.h"
|
||||
#include "ovms_peripherals.h"
|
||||
|
||||
#define UDP_TIMEOUT 30
|
||||
|
||||
canlog_udpserver* MyCanLogUdpServer = NULL;
|
||||
|
||||
udpcanlogconnection::udpcanlogconnection(canlog* logger, std::string format, canformat::canformat_serve_mode_t mode)
|
||||
: canlogconnection(logger, format, mode)
|
||||
{
|
||||
m_timeout = monotonictime + UDP_TIMEOUT;
|
||||
}
|
||||
|
||||
udpcanlogconnection::~udpcanlogconnection()
|
||||
{
|
||||
}
|
||||
|
||||
void udpcanlogconnection::OutputMsg(CAN_log_message_t& msg, std::string &result)
|
||||
{
|
||||
m_msgcount++;
|
||||
|
||||
if ((m_filters != NULL) && (! m_filters->IsFiltered(&msg.frame)))
|
||||
{
|
||||
m_filtercount++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.length()>0)
|
||||
{
|
||||
sendto(m_sock, (const char*)result.c_str(), result.length(), 0, &m_sa, sizeof(m_sa));
|
||||
}
|
||||
}
|
||||
|
||||
void udpcanlogconnection::Tickle()
|
||||
{
|
||||
m_timeout = monotonictime + UDP_TIMEOUT;
|
||||
}
|
||||
|
||||
void can_log_udpserver_start(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
|
||||
{
|
||||
std::string format(cmd->GetName());
|
||||
std::string mode(cmd->GetParent()->GetName());
|
||||
canlog_udpserver* logger = new canlog_udpserver(argv[0],format,GetFormatModeType(mode));
|
||||
|
||||
if (logger->Open())
|
||||
{
|
||||
if (argc>1)
|
||||
{ MyCan.AddLogger(logger, argc-1, &argv[1]); }
|
||||
else
|
||||
{ MyCan.AddLogger(logger); }
|
||||
writer->printf("CAN logging as UDP server: %s\n", logger->GetInfo().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
writer->printf("Error: Could not start CAN logging as UDP server: %s\n",logger->GetInfo().c_str());
|
||||
delete logger;
|
||||
}
|
||||
}
|
||||
|
||||
class OvmsCanLogUdpServerInit
|
||||
{
|
||||
public:
|
||||
OvmsCanLogUdpServerInit();
|
||||
void NetManInit(std::string event, void* data);
|
||||
void NetManStop(std::string event, void* data);
|
||||
} MyOvmsCanLogUdpServerInit __attribute__ ((init_priority (4560)));
|
||||
|
||||
OvmsCanLogUdpServerInit::OvmsCanLogUdpServerInit()
|
||||
{
|
||||
ESP_LOGI(TAG, "Initialising CAN logging as UDP server (4560)");
|
||||
|
||||
OvmsCommand* cmd_can = MyCommandApp.FindCommand("can");
|
||||
if (cmd_can)
|
||||
{
|
||||
OvmsCommand* cmd_can_log = cmd_can->FindCommand("log");
|
||||
if (cmd_can_log)
|
||||
{
|
||||
OvmsCommand* cmd_can_log_start = cmd_can_log->FindCommand("start");
|
||||
if (cmd_can_log_start)
|
||||
{
|
||||
// We have a place to put our command tree..
|
||||
OvmsCommand* start = cmd_can_log_start->RegisterCommand("udpserver", "CAN logging as UDP server");
|
||||
OvmsCommand* discard = start->RegisterCommand("discard","CAN logging as UDP server (discard mode)");
|
||||
OvmsCommand* simulate = start->RegisterCommand("simulate","CAN logging as UDP server (simulate mode)");
|
||||
OvmsCommand* transmit = start->RegisterCommand("transmit","CAN logging as UDP server (transmit mode)");
|
||||
MyCanFormatFactory.RegisterCommandSet(discard, "Start CAN logging as UDP server (discard mode)",
|
||||
can_log_udpserver_start,
|
||||
"<port> [filter1] ... [filterN]\n"
|
||||
"Filter: <bus> | <id>[-<id>] | <bus>:<id>[-<id>]\n"
|
||||
"Example: 2:2a0-37f",
|
||||
1, 9);
|
||||
MyCanFormatFactory.RegisterCommandSet(simulate, "Start CAN logging as UDP server (simulate mode)",
|
||||
can_log_udpserver_start,
|
||||
"<port> [filter1] ... [filterN]\n"
|
||||
"Filter: <bus> | <id>[-<id>] | <bus>:<id>[-<id>]\n"
|
||||
"Example: 2:2a0-37f",
|
||||
1, 9);
|
||||
MyCanFormatFactory.RegisterCommandSet(transmit, "Start CAN logging as UDP server (transmit mode)",
|
||||
can_log_udpserver_start,
|
||||
"<port> [filter1] ... [filterN]\n"
|
||||
"Filter: <bus> | <id>[-<id>] | <bus>:<id>[-<id>]\n"
|
||||
"Example: 2:2a0-37f",
|
||||
1, 9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
MyEvents.RegisterEvent(TAG, "network.mgr.init", std::bind(&OvmsCanLogUdpServerInit::NetManInit, this, _1, _2));
|
||||
MyEvents.RegisterEvent(TAG, "network.mgr.stop", std::bind(&OvmsCanLogUdpServerInit::NetManStop, this, _1, _2));
|
||||
}
|
||||
|
||||
void OvmsCanLogUdpServerInit::NetManInit(std::string event, void* data)
|
||||
{
|
||||
if (MyCanLogUdpServer) MyCanLogUdpServer->Open();
|
||||
}
|
||||
|
||||
void OvmsCanLogUdpServerInit::NetManStop(std::string event, void* data)
|
||||
{
|
||||
if (MyCanLogUdpServer) MyCanLogUdpServer->Close();
|
||||
}
|
||||
|
||||
static void tsMongooseHandler(struct mg_connection *nc, int ev, void *p)
|
||||
{
|
||||
if (MyCanLogUdpServer)
|
||||
MyCanLogUdpServer->MongooseHandler(nc, ev, p);
|
||||
else if (ev == MG_EV_ACCEPT)
|
||||
{
|
||||
ESP_LOGI(TAG, "Log service connection rejected (logger not running)");
|
||||
nc->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
}
|
||||
}
|
||||
|
||||
canlog_udpserver::canlog_udpserver(std::string path, std::string format, canformat::canformat_serve_mode_t mode)
|
||||
: canlog("udpserver", format, mode)
|
||||
{
|
||||
MyCanLogUdpServer = this;
|
||||
m_path = path;
|
||||
if (m_path.find(':') == std::string::npos)
|
||||
{
|
||||
m_path.insert(0, "udp://");
|
||||
}
|
||||
m_isopen = false;
|
||||
m_mgconn = NULL;
|
||||
|
||||
#undef bind // Kludgy, but works
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
MyEvents.RegisterEvent(TAG,"ticker.10", std::bind(&canlog_udpserver::Ticker, this, _1, _2));
|
||||
}
|
||||
|
||||
canlog_udpserver::~canlog_udpserver()
|
||||
{
|
||||
Close();
|
||||
MyCanLogUdpServer = NULL;
|
||||
MyEvents.DeregisterEvent(TAG);
|
||||
}
|
||||
|
||||
bool canlog_udpserver::Open()
|
||||
{
|
||||
if (m_isopen) return true;
|
||||
|
||||
ESP_LOGI(TAG, "Launching UDP server at %s",m_path.c_str());
|
||||
struct mg_mgr* mgr = MyNetManager.GetMongooseMgr();
|
||||
if (mgr != NULL)
|
||||
{
|
||||
if (MyNetManager.m_network_any)
|
||||
{
|
||||
m_mgconn = mg_bind(mgr, m_path.c_str(), tsMongooseHandler);
|
||||
if (m_mgconn != NULL)
|
||||
{
|
||||
ESP_LOGI(TAG,"Listening with nc %p",m_mgconn);
|
||||
m_isopen = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG,"Could not listen on %s",m_path.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG,"Delay UDP server (as network manager not up)");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG,"Network manager is not available");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void canlog_udpserver::Close()
|
||||
{
|
||||
if (m_isopen)
|
||||
{
|
||||
if (m_connmap.size() > 0)
|
||||
{
|
||||
OvmsRecMutexLock lock(&m_cmmutex);
|
||||
for (conn_map_t::iterator it=m_connmap.begin(); it!=m_connmap.end(); ++it)
|
||||
{
|
||||
it->first->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
delete it->second;
|
||||
}
|
||||
m_connmap.clear();
|
||||
}
|
||||
ESP_LOGI(TAG, "Closed UDP server log: %s", GetStats().c_str());
|
||||
m_mgconn->flags |= MG_F_CLOSE_IMMEDIATELY;
|
||||
m_mgconn = NULL;
|
||||
m_isopen = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string canlog_udpserver::GetInfo()
|
||||
{
|
||||
std::string result = canlog::GetInfo();
|
||||
result.append(" Path:");
|
||||
result.append(m_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
void canlog_udpserver::Ticker(std::string event, void* data)
|
||||
{
|
||||
OvmsRecMutexLock lock(&m_cmmutex);
|
||||
|
||||
for (conn_map_t::iterator it=m_connmap.begin(); it!=m_connmap.end(); ++it)
|
||||
{
|
||||
udpcanlogconnection* clc = (udpcanlogconnection*)it->second;
|
||||
if (clc->m_timeout < monotonictime)
|
||||
{
|
||||
// This client has timed out
|
||||
ESP_LOGD(TAG,"Timed out connection from %s",clc->m_peer.c_str());
|
||||
m_connmap.erase(it);
|
||||
delete clc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void canlog_udpserver::MongooseHandler(struct mg_connection *nc, int ev, void *p)
|
||||
{
|
||||
char addr[32];
|
||||
|
||||
switch (ev)
|
||||
{
|
||||
case MG_EV_RECV:
|
||||
{
|
||||
OvmsRecMutexLock lock(&m_cmmutex);
|
||||
mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), MG_SOCK_STRINGIFY_IP|MG_SOCK_STRINGIFY_PORT);
|
||||
|
||||
size_t used = nc->recv_mbuf.len;
|
||||
|
||||
// Try to find an existing matching connection
|
||||
udpcanlogconnection* clc = NULL;
|
||||
for (conn_map_t::iterator it=m_connmap.begin(); it!=m_connmap.end(); ++it)
|
||||
{
|
||||
clc = (udpcanlogconnection*)it->second;
|
||||
if (memcmp(&clc->m_sa, &nc->sa, sizeof(&nc->sa.sin)) == 0)
|
||||
{
|
||||
// We have found an existing one, so just handle and tickle it
|
||||
ESP_LOGD(TAG,"Tickle connection from %s",addr);
|
||||
used = clc->m_formatter->Serve((uint8_t*)nc->recv_mbuf.buf, used, clc);
|
||||
if (used>0) mbuf_remove(&nc->recv_mbuf, used);
|
||||
clc->Tickle();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No matching connection, so make a new one
|
||||
ESP_LOGD(TAG,"New connection from %s",addr);
|
||||
clc = new udpcanlogconnection(this, m_format, m_mode);
|
||||
clc->m_nc = m_mgconn;
|
||||
clc->m_sock = m_mgconn->sock;
|
||||
memcpy(&clc->m_sa,&nc->sa.sin,sizeof(nc->sa.sin));
|
||||
clc->m_peer = std::string(addr);
|
||||
m_connmap[&clc->m_fakenc] = clc;
|
||||
std::string result = clc->m_formatter->getheader();
|
||||
if (result.length()>0)
|
||||
{
|
||||
mg_send(nc, (const char*)result.c_str(), result.length());
|
||||
}
|
||||
used = clc->m_formatter->Serve((uint8_t*)nc->recv_mbuf.buf, used, clc);
|
||||
if (used > 0) mbuf_remove(&nc->recv_mbuf, used);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifdef CONFIG_OVMS_SC_GPL_MONGOOSE
|
80
OVMS.V3/components/can/src/canlog_udpserver.h
Normal file
80
OVMS.V3/components/can/src/canlog_udpserver.h
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Module: CAN logging framework
|
||||
; Date: 18th January 2018
|
||||
;
|
||||
; (C) 2018 Michael Balzer
|
||||
; (C) 2019 Mark Webb-Johnson
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __CANLOG_UDP_SERVER_H__
|
||||
#define __CANLOG_UDP_SERVER_H__
|
||||
|
||||
#include <sdkconfig.h>
|
||||
#ifdef CONFIG_OVMS_SC_GPL_MONGOOSE
|
||||
|
||||
#include "canlog.h"
|
||||
#include "ovms_netmanager.h"
|
||||
#include "ovms_mutex.h"
|
||||
|
||||
class udpcanlogconnection: public canlogconnection
|
||||
{
|
||||
public:
|
||||
udpcanlogconnection(canlog* logger, std::string format, canformat::canformat_serve_mode_t mode);
|
||||
virtual ~udpcanlogconnection();
|
||||
|
||||
public:
|
||||
virtual void OutputMsg(CAN_log_message_t& msg, std::string &result);
|
||||
|
||||
public:
|
||||
void Tickle();
|
||||
|
||||
public:
|
||||
sock_t m_sock; // Our main listening UDP socket
|
||||
struct sockaddr m_sa; // Our remote client address
|
||||
mg_connection m_fakenc; // A fake nc, just as an index to us
|
||||
uint32_t m_timeout; // Our timeout
|
||||
};
|
||||
|
||||
class canlog_udpserver : public canlog
|
||||
{
|
||||
public:
|
||||
canlog_udpserver(std::string path, std::string format, canformat::canformat_serve_mode_t mode);
|
||||
virtual ~canlog_udpserver();
|
||||
|
||||
public:
|
||||
virtual bool Open();
|
||||
virtual void Close();
|
||||
virtual std::string GetInfo();
|
||||
|
||||
public:
|
||||
void MongooseHandler(struct mg_connection *nc, int ev, void *p);
|
||||
void Ticker(std::string event, void* data);
|
||||
|
||||
public:
|
||||
struct mg_connection *m_mgconn;
|
||||
|
||||
public:
|
||||
std::string m_path;
|
||||
};
|
||||
|
||||
#endif // #ifdef CONFIG_OVMS_SC_GPL_MONGOOSE
|
||||
#endif // __CANLOG_UDP_SERVER_H__
|
|
@ -89,7 +89,7 @@ OvmsCanLogVFSInit::OvmsCanLogVFSInit()
|
|||
|
||||
|
||||
canlog_vfs_conn::canlog_vfs_conn(canlog* logger, std::string format, canformat::canformat_serve_mode_t mode)
|
||||
: canlogconnection(logger, format, mode)
|
||||
: canlogconnection(logger, format, mode), m_file_size(0)
|
||||
{
|
||||
m_file = NULL;
|
||||
}
|
||||
|
@ -114,7 +114,10 @@ void canlog_vfs_conn::OutputMsg(CAN_log_message_t& msg, std::string &result)
|
|||
}
|
||||
|
||||
if (result.length()>0)
|
||||
{
|
||||
fwrite(result.c_str(),result.length(),1,m_file);
|
||||
m_file_size += result.length();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -181,7 +184,10 @@ bool canlog_vfs::Open()
|
|||
|
||||
std::string header = m_formatter->getheader();
|
||||
if (header.length()>0)
|
||||
{
|
||||
fwrite(header.c_str(),header.length(),1,clc->m_file);
|
||||
clc->m_file_size += header.length();
|
||||
}
|
||||
|
||||
m_connmap[NULL] = clc;
|
||||
m_isopen = true;
|
||||
|
@ -207,6 +213,47 @@ void canlog_vfs::Close()
|
|||
}
|
||||
}
|
||||
|
||||
size_t canlog_vfs::GetFileSize()
|
||||
{
|
||||
size_t result = 0;
|
||||
if (m_isopen)
|
||||
{
|
||||
for (conn_map_t::iterator it=m_connmap.begin(); it!=m_connmap.end(); ++it)
|
||||
{
|
||||
canlog_vfs_conn * clc = static_cast<canlog_vfs_conn *>(it->second);
|
||||
result += clc->m_file_size;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string canlog_vfs_conn::GetStats()
|
||||
{
|
||||
char bufsize[15];
|
||||
format_file_size(bufsize, sizeof(bufsize), m_file_size);
|
||||
|
||||
std::string result = "Size:";
|
||||
result.append(bufsize);
|
||||
result.append(" ");
|
||||
result.append(canlogconnection::GetStats());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string canlog_vfs::GetStats()
|
||||
{
|
||||
char bufsize[15];
|
||||
size_t size = GetFileSize();
|
||||
format_file_size(bufsize, sizeof(bufsize), size);
|
||||
|
||||
std::string result = "Size:";
|
||||
result.append(bufsize);
|
||||
result.append(" ");
|
||||
result.append(canlog::GetStats());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string canlog_vfs::GetInfo()
|
||||
{
|
||||
std::string result = canlog::GetInfo();
|
||||
|
|
|
@ -39,9 +39,11 @@ class canlog_vfs_conn: public canlogconnection
|
|||
|
||||
public:
|
||||
virtual void OutputMsg(CAN_log_message_t& msg, std::string &result);
|
||||
virtual std::string GetStats();
|
||||
|
||||
public:
|
||||
FILE* m_file;
|
||||
size_t m_file_size;
|
||||
};
|
||||
|
||||
|
||||
|
@ -55,9 +57,11 @@ class canlog_vfs : public canlog
|
|||
virtual bool Open();
|
||||
virtual void Close();
|
||||
virtual std::string GetInfo();
|
||||
virtual size_t GetFileSize();
|
||||
|
||||
public:
|
||||
virtual void MountListener(std::string event, void* data);
|
||||
virtual std::string GetStats();
|
||||
|
||||
public:
|
||||
std::string m_path;
|
||||
|
|
|
@ -158,6 +158,7 @@ OvmsSSH::OvmsSSH()
|
|||
using std::placeholders::_2;
|
||||
MyEvents.RegisterEvent(tag,"network.mgr.init", std::bind(&OvmsSSH::NetManInit, this, _1, _2));
|
||||
MyEvents.RegisterEvent(tag,"network.mgr.stop", std::bind(&OvmsSSH::NetManStop, this, _1, _2));
|
||||
MyEvents.RegisterEvent(tag,"config.restore", std::bind(&OvmsSSH::ConfigRestore, this, _1, _2));
|
||||
MyConfig.RegisterParam("ssh.server", "SSH server private key store", true, false);
|
||||
MyConfig.RegisterParam("ssh.info", "SSH server information", false, true);
|
||||
MyConfig.RegisterParam("ssh.keys", "SSH public key store", true, true);
|
||||
|
@ -232,6 +233,14 @@ void OvmsSSH::NetManStop(std::string event, void* data)
|
|||
}
|
||||
}
|
||||
|
||||
void OvmsSSH::ConfigRestore(std::string event, void* data)
|
||||
{
|
||||
if (RSAKeyGenerator::KillInstance())
|
||||
{
|
||||
ESP_LOGW(tag, "RSAKeyGenerator killed by request");
|
||||
}
|
||||
}
|
||||
|
||||
int OvmsSSH::Authenticate(uint8_t type, WS_UserAuthData* data, void* ctx)
|
||||
{
|
||||
ConsoleSSH* cons = (ConsoleSSH*)ctx;
|
||||
|
@ -1058,11 +1067,26 @@ int SendCallback(WOLFSSH* ssh, void* data, uint32_t size, void* ctx)
|
|||
// Class RSAKeyGenerator
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
RSAKeyGenerator* RSAKeyGenerator::s_instance = NULL;
|
||||
|
||||
RSAKeyGenerator::RSAKeyGenerator() : TaskBase("RSAKeyGen", 7*1024, 0)
|
||||
{
|
||||
s_instance = this;
|
||||
Instantiate();
|
||||
}
|
||||
|
||||
RSAKeyGenerator::~RSAKeyGenerator()
|
||||
{
|
||||
s_instance = NULL;
|
||||
}
|
||||
|
||||
bool RSAKeyGenerator::KillInstance()
|
||||
{
|
||||
if (!s_instance) return false;
|
||||
s_instance->Kill();
|
||||
return true;
|
||||
}
|
||||
|
||||
void RSAKeyGenerator::Service()
|
||||
{
|
||||
// Generate a random 2048-bit SSH host key for the SSH server in DER format.
|
||||
|
|
|
@ -49,6 +49,7 @@ class OvmsSSH
|
|||
void EventHandler(struct mg_connection *nc, int ev, void *p);
|
||||
void NetManInit(std::string event, void* data);
|
||||
void NetManStop(std::string event, void* data);
|
||||
void ConfigRestore(std::string event, void* data);
|
||||
static int Authenticate(uint8_t type, WS_UserAuthData* data, void* ctx);
|
||||
WOLFSSH_CTX* ctx() { return m_ctx; }
|
||||
|
||||
|
@ -74,7 +75,7 @@ class ConsoleSSH : public OvmsConsole
|
|||
void Sent();
|
||||
void Exit();
|
||||
int puts(const char* s);
|
||||
int printf(const char* fmt, ...);
|
||||
int printf(const char* fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
ssize_t write(const void *buf, size_t nbyte);
|
||||
int RecvCallback(char* buf, uint32_t size);
|
||||
bool IsDraining() { return m_drain > 0; }
|
||||
|
@ -118,14 +119,18 @@ class ConsoleSSH : public OvmsConsole
|
|||
|
||||
class RSAKeyGenerator : public TaskBase
|
||||
{
|
||||
private:
|
||||
static RSAKeyGenerator* s_instance;
|
||||
|
||||
public:
|
||||
RSAKeyGenerator();
|
||||
virtual ~RSAKeyGenerator() {}
|
||||
virtual ~RSAKeyGenerator();
|
||||
static bool KillInstance();
|
||||
|
||||
private:
|
||||
void Service();
|
||||
|
||||
private:
|
||||
byte m_der[1200]; // Big enough for 2048-bit private key
|
||||
byte m_der[1200]; // Big enough for 2048-bit private key
|
||||
};
|
||||
#endif //#ifndef __CONSOLE_SSH_H__
|
||||
|
|
|
@ -64,7 +64,7 @@ class ConsoleTelnet : public OvmsConsole
|
|||
void Receive();
|
||||
void Exit();
|
||||
int puts(const char* s);
|
||||
int printf(const char* fmt, ...);
|
||||
int printf(const char* fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
ssize_t write(const void *buf, size_t nbyte);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -19,6 +19,10 @@ COMPONENT_SRCDIRS:=src yacclex
|
|||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
COMPONENT_OBJS = src/dbc_app.o src/dbc_number.o src/dbc.o yacclex/dbc_tokeniser.o yacclex/dbc_parser.o
|
||||
|
||||
# silence warning about unused yy_flex_strncpy()
|
||||
CFLAGS += -Wno-unused-function
|
||||
CXXFLAGS += -Wno-unused-function
|
||||
|
||||
COMPONENT_EXTRA_CLEAN := $(COMPONENT_PATH)/yacclex/dbc_tokeniser.cpp \
|
||||
$(COMPONENT_PATH)/yacclex/dbc_tokeniser.c \
|
||||
$(COMPONENT_PATH)/yacclex/dbc_tokeniser.hpp \
|
||||
|
|
|
@ -830,8 +830,10 @@ dbcNumber dbcSignal::Decode(CAN_frame_t* msg)
|
|||
|
||||
if (m_value_type == DBC_VALUETYPE_UNSIGNED)
|
||||
result.Cast((uint32_t)val, DBC_NUMBER_INTEGER_UNSIGNED);
|
||||
else
|
||||
result.Cast((uint32_t)val, DBC_NUMBER_INTEGER_SIGNED);
|
||||
else {
|
||||
int32_t signed_val = sign_extend<uint32_t, int32_t>((uint32_t)val, m_signal_size-1);
|
||||
result.Cast(static_cast<uint32_t>(signed_val), DBC_NUMBER_INTEGER_SIGNED);
|
||||
}
|
||||
|
||||
// Apply factor and offset
|
||||
if (!(m_factor == 1))
|
||||
|
|
|
@ -191,12 +191,28 @@ void GsmNMEA::IncomingLine(const std::string line)
|
|||
*StdMetrics.ms_v_pos_gpsmode = (std::string) mode;
|
||||
*StdMetrics.ms_v_pos_satcount = (int) satcnt;
|
||||
*StdMetrics.ms_v_pos_gpshdop = (float) hdop;
|
||||
|
||||
// Derive signal quality from lock status, satellite count and HDOP:
|
||||
// quality ~ satcnt / hdop
|
||||
*StdMetrics.ms_v_pos_gpssq = (int) LIMIT_MAX(gpslock * LIMIT_MIN(satcnt-1,0) / LIMIT_MIN(hdop,0.1) * 10, 100);
|
||||
// Quality raises by satellite count and drops by HDOP. HDOP 1.0 = perfect.
|
||||
// The calculation is designed to get 50% as the threshold for a "good" signal.
|
||||
// GPS needs at least 4 satellites in view to get a position, but that will need
|
||||
// HDOP << 1 to be considered reliable. 6 satellites are on the edge to "good"
|
||||
// (with HDOP=1). Samples:
|
||||
// 4 satellites / HDOP 1.0 → SQ 30%
|
||||
// 4 satellites / HDOP 0.6 → SQ 50%
|
||||
// 6 satellites / HDOP 1.0 → SQ 50%
|
||||
// 9 satellites / HDOP 1.0 → SQ 80%
|
||||
// 10 satellites / HDOP 0.9 → SQ 100%
|
||||
// 10 satellites / HDOP 1.8 → SQ 50%
|
||||
|
||||
if (gpslock)
|
||||
{
|
||||
*StdMetrics.ms_v_pos_latitude = (float) lat;
|
||||
*StdMetrics.ms_v_pos_longitude = (float) lon;
|
||||
*StdMetrics.ms_v_pos_altitude = (float) alt;
|
||||
*StdMetrics.ms_v_pos_gpstime = (int) time(NULL);
|
||||
}
|
||||
|
||||
// upodate gpslock last, so listeners will see updated lat/lon values:
|
||||
|
@ -281,6 +297,12 @@ void GsmNMEA::Shutdown(bool hard)
|
|||
{
|
||||
ESP_LOGI(TAG, "Shutdown (direct)");
|
||||
|
||||
*StdMetrics.ms_v_pos_gpsmode = (std::string) "";
|
||||
*StdMetrics.ms_v_pos_gpsspeed = (float) 0;
|
||||
*StdMetrics.ms_v_pos_satcount = (int) 0;
|
||||
*StdMetrics.ms_v_pos_gpshdop = (float) 500;
|
||||
*StdMetrics.ms_v_pos_gpssq = (int) 0;
|
||||
|
||||
if (StdMetrics.ms_v_pos_gpslock->AsBool())
|
||||
{
|
||||
*StdMetrics.ms_v_pos_gpslock = (bool) false;
|
||||
|
|
|
@ -79,12 +79,16 @@ const char* ModemNetRegName(modem::network_registration_t netreg)
|
|||
{
|
||||
switch (netreg)
|
||||
{
|
||||
case modem::NotRegistered: return "NotRegistered";
|
||||
case modem::Searching: return "Searching";
|
||||
case modem::DeniedRegistration: return "DeniedRegistration";
|
||||
case modem::RegisteredHome: return "RegisteredHome";
|
||||
case modem::RegisteredRoaming: return "RegisteredRoaming";
|
||||
default: return "Unknown";
|
||||
case modem::NotRegistered: return "NotRegistered";
|
||||
case modem::DeniedRegistration: return "DeniedRegistration";
|
||||
case modem::Searching: return "Searching";
|
||||
case modem::Registered: return "Registered";
|
||||
case modem::RegisteredEmergencyServices: return "RegisteredEmergencyServices";
|
||||
case modem::RegisteredRoamingSMS: return "RegisteredRoamingSMS";
|
||||
case modem::RegisteredRoaming: return "RegisteredRoaming";
|
||||
case modem::RegisteredHomeSMS: return "RegisteredHomeSMS";
|
||||
case modem::RegisteredHome: return "RegisteredHome";
|
||||
default: return "Unknown";
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -115,7 +119,7 @@ void modem::Task()
|
|||
.use_ref_tick = 0,
|
||||
};
|
||||
uart_param_config(m_uartnum, &uart_config);
|
||||
uart_set_pin(m_uartnum, m_txpin, m_rxpin, 0, 0);
|
||||
uart_set_pin(m_uartnum, m_txpin, m_rxpin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
uart_driver_install(m_uartnum,
|
||||
CONFIG_OVMS_HW_CELLULAR_MODEM_UART_SIZE,
|
||||
CONFIG_OVMS_HW_CELLULAR_MODEM_UART_SIZE,
|
||||
|
@ -241,11 +245,20 @@ void modem::Task()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_state1 == PoweredOff && MyBoot.IsShuttingDown())
|
||||
{
|
||||
m_task = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown:
|
||||
uart_driver_delete(m_uartnum);
|
||||
ESP_LOGD(TAG, "UART shutdown");
|
||||
m_queue = 0;
|
||||
uart_wait_tx_done(m_uartnum, portMAX_DELAY);
|
||||
uart_flush(m_uartnum);
|
||||
uart_driver_delete(m_uartnum);
|
||||
if (MyBoot.IsShuttingDown()) MyBoot.ShutdownReady(TAG);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
|
@ -272,6 +285,7 @@ modem::modem(const char* name, uart_port_t uartnum, int baud, int rxpin, int txp
|
|||
m_line_unfinished = -1;
|
||||
m_line_buffer.clear();
|
||||
m_netreg = Unknown;
|
||||
for (size_t k=0; k<CELLULAR_NETREG_COUNT; k++) { m_netreg_d[k] = Unknown; }
|
||||
m_provider = "";
|
||||
m_sq = 99; // Unknown
|
||||
m_powermode = Off;
|
||||
|
@ -285,6 +299,8 @@ modem::modem(const char* name, uart_port_t uartnum, int baud, int rxpin, int txp
|
|||
m_mux = NULL;
|
||||
m_ppp = NULL;
|
||||
m_driver = NULL;
|
||||
m_cmd_running = false;
|
||||
m_cmd_output.clear();
|
||||
|
||||
ClearNetMetrics();
|
||||
StartTask();
|
||||
|
@ -402,6 +418,9 @@ void modem::SupportSummary(OvmsWriter* writer, bool debug /*=FALSE*/)
|
|||
m_provider.c_str(),
|
||||
UnitConvert(sq, dbm, m_sq),
|
||||
StandardMetrics.ms_m_net_mdm_mode->AsString().c_str());
|
||||
// writer->printf(" GSM Registration: %s\n",ModemNetRegName(m_netreg_d[NRT_GSM]));
|
||||
// writer->printf(" GPRS Registration: %s\n",ModemNetRegName(m_netreg_d[NRT_GPRS]));
|
||||
// writer->printf(" EPS Registration: %s\n",ModemNetRegName(m_netreg_d[NRT_EPS]));
|
||||
}
|
||||
|
||||
writer->printf(" State: %s\n", ModemState1Name(m_state1));
|
||||
|
@ -652,7 +671,6 @@ void modem::State1Enter(modem_state1_t newstate)
|
|||
case PoweredOff:
|
||||
ClearNetMetrics();
|
||||
MyEvents.SignalEvent("system.modem.poweredoff", NULL);
|
||||
if (MyBoot.IsShuttingDown()) MyBoot.ShutdownReady(TAG);
|
||||
StopMux();
|
||||
if (m_driver)
|
||||
{
|
||||
|
@ -832,7 +850,7 @@ modem::modem_state1_t modem::State1Ticker1()
|
|||
if (m_mux != NULL)
|
||||
{
|
||||
if ((m_state1_ticker>5)&&((m_state1_ticker % 30) == 0))
|
||||
{ muxtx(m_mux_channel_POLL, "AT+CREG?;+CCLK?;+CSQ;+COPS?\r\n"); }
|
||||
{ m_driver->StatusPoller(); }
|
||||
if (m_mux->IsMuxUp())
|
||||
return NetWait;
|
||||
}
|
||||
|
@ -850,10 +868,10 @@ modem::modem_state1_t modem::State1Ticker1()
|
|||
if ((!MyConfig.GetParamValueBool("modem", "enable.net", true))||(p.empty()))
|
||||
return NetHold; // Just hold, without starting PPP
|
||||
}
|
||||
else if ((m_state1_ticker > 3)&&((m_netreg==RegisteredHome)||(m_netreg==RegisteredRoaming)))
|
||||
else if ((m_state1_ticker > 3)&&((m_netreg >= Registered)))
|
||||
return NetStart; // We have GSM, so start the network
|
||||
if ((m_mux != NULL)&&(m_state1_ticker>3)&&((m_state1_ticker % 10) == 0))
|
||||
{ muxtx(m_mux_channel_POLL, "AT+CREG?;+CCLK?;+CSQ;+COPS?\r\n"); }
|
||||
{ m_driver->StatusPoller(); }
|
||||
break;
|
||||
|
||||
case NetStart:
|
||||
|
@ -889,14 +907,14 @@ modem::modem_state1_t modem::State1Ticker1()
|
|||
|
||||
case NetHold:
|
||||
if ((m_mux != NULL)&&(m_state1_ticker>5)&&((m_state1_ticker % 30) == 0))
|
||||
{ muxtx(m_mux_channel_POLL, "AT+CREG?;+CCLK?;+CSQ;+COPS?\r\n"); }
|
||||
{ m_driver->StatusPoller(); }
|
||||
break;
|
||||
|
||||
case NetSleep:
|
||||
if (m_powermode == On) return NetWait;
|
||||
if (m_powermode != Sleep) return PoweringOn;
|
||||
if ((m_mux != NULL)&&(m_state1_ticker>5)&&((m_state1_ticker % 30) == 0))
|
||||
{ muxtx(m_mux_channel_POLL, "AT+CREG?;+CCLK?;+CSQ;+COPS?\r\n"); }
|
||||
{ m_driver->StatusPoller(); }
|
||||
break;
|
||||
|
||||
case NetMode:
|
||||
|
@ -905,7 +923,7 @@ modem::modem_state1_t modem::State1Ticker1()
|
|||
// Need to shutdown ppp, and get back to NetSleep mode
|
||||
return NetSleep;
|
||||
}
|
||||
if ((m_netreg!=RegisteredHome)&&(m_netreg!=RegisteredRoaming))
|
||||
if (m_netreg < Registered)
|
||||
{
|
||||
// We've lost the network connection
|
||||
ESP_LOGW(TAG, "Lost network connection (NetworkRegistration in NetMode)");
|
||||
|
@ -988,6 +1006,12 @@ void modem::StandardLineHandler(int channel, OvmsBuffer* buf, std::string line)
|
|||
if (line.length() == 0)
|
||||
return;
|
||||
|
||||
if ((m_cmd_running)&&(channel == m_mux_channel_CMD))
|
||||
{
|
||||
m_cmd_output.append(line);
|
||||
m_cmd_output.append("\r\n");
|
||||
}
|
||||
|
||||
// expecting continuation of previous line?
|
||||
if (m_line_unfinished == channel)
|
||||
{
|
||||
|
@ -1002,13 +1026,16 @@ void modem::StandardLineHandler(int channel, OvmsBuffer* buf, std::string line)
|
|||
line = m_line_buffer;
|
||||
}
|
||||
|
||||
const char *cp = line.c_str();
|
||||
if ((line.length()>2)&&(cp[0]!='$')&&(cp[1])!='G')
|
||||
if (line.compare(0, 2, "$G") == 0)
|
||||
{
|
||||
// Log incoming data other than GPS NMEA
|
||||
ESP_LOGD(TAG, "mux-rx-line #%d: %s", channel, line.c_str());
|
||||
// GPS NMEA URC:
|
||||
if (m_nmea) m_nmea->IncomingLine(line);
|
||||
return;
|
||||
}
|
||||
|
||||
// Log incoming data other than GPS NMEA
|
||||
ESP_LOGD(TAG, "mux-rx-line #%d: %s", channel, line.c_str());
|
||||
|
||||
if ((line.compare(0, 8, "CONNECT ") == 0)&&(m_state1 == NetStart)&&(m_state1_userdata == 1))
|
||||
{
|
||||
ESP_LOGI(TAG, "PPP Connection is ready to start");
|
||||
|
@ -1047,26 +1074,57 @@ void modem::StandardLineHandler(int channel, OvmsBuffer* buf, std::string line)
|
|||
creg = atoi(line.substr(7,1).c_str());
|
||||
switch (creg)
|
||||
{
|
||||
case 0:
|
||||
case 4:
|
||||
nreg = NotRegistered;
|
||||
break;
|
||||
case 1:
|
||||
nreg = RegisteredHome;
|
||||
break;
|
||||
case 2:
|
||||
nreg = Searching;
|
||||
break;
|
||||
case 3:
|
||||
nreg = DeniedRegistration;
|
||||
break;
|
||||
case 5:
|
||||
nreg = RegisteredRoaming;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case 0: case 4: nreg = NotRegistered; break;
|
||||
case 1: nreg = RegisteredHome; break;
|
||||
case 2: nreg = Searching; break;
|
||||
case 3: nreg = DeniedRegistration; break;
|
||||
case 5: nreg = RegisteredRoaming; break;
|
||||
default: break;
|
||||
}
|
||||
SetNetworkRegistration(nreg);
|
||||
SetNetworkRegistration(NRT_GSM, nreg);
|
||||
}
|
||||
else if (line.compare(0, 8, "+CGREG: ") == 0)
|
||||
{
|
||||
size_t qp = line.find(',');
|
||||
int creg;
|
||||
network_registration_t nreg = Unknown;
|
||||
if (qp != string::npos)
|
||||
creg = atoi(line.substr(qp+1,1).c_str());
|
||||
else
|
||||
creg = atoi(line.substr(7,1).c_str());
|
||||
switch (creg)
|
||||
{
|
||||
case 0: case 4: nreg = NotRegistered; break;
|
||||
case 1: nreg = RegisteredHome; break;
|
||||
case 2: nreg = Searching; break;
|
||||
case 3: nreg = DeniedRegistration; break;
|
||||
case 5: nreg = RegisteredRoaming; break;
|
||||
default: break;
|
||||
}
|
||||
SetNetworkRegistration(NRT_GPRS, nreg);
|
||||
}
|
||||
else if (line.compare(0, 8, "+CEREG: ") == 0)
|
||||
{
|
||||
size_t qp = line.find(',');
|
||||
int creg;
|
||||
network_registration_t nreg = Unknown;
|
||||
if (qp != string::npos)
|
||||
creg = atoi(line.substr(qp+1,1).c_str());
|
||||
else
|
||||
creg = atoi(line.substr(7,1).c_str());
|
||||
switch (creg)
|
||||
{
|
||||
case 0: case 4: nreg = NotRegistered; break;
|
||||
case 1: nreg = RegisteredHome; break;
|
||||
case 2: nreg = Searching; break;
|
||||
case 3: nreg = DeniedRegistration; break;
|
||||
case 5: nreg = RegisteredRoaming; break;
|
||||
case 6: nreg = RegisteredHomeSMS; break;
|
||||
case 7: nreg = RegisteredRoamingSMS; break;
|
||||
case 8: nreg = RegisteredEmergencyServices; break;
|
||||
default: break;
|
||||
}
|
||||
SetNetworkRegistration(NRT_EPS, nreg);
|
||||
}
|
||||
else if (line.compare(0, 7, "+CPSI: ") == 0)
|
||||
{
|
||||
|
@ -1128,15 +1186,22 @@ void modem::StandardLineHandler(int channel, OvmsBuffer* buf, std::string line)
|
|||
}
|
||||
else if (line.compare(0, 30, "+CME ERROR: incorrect password") == 0)
|
||||
{
|
||||
std::string pincode = MyConfig.GetParamValue("modem", "pincode");
|
||||
ESP_LOGE(TAG,"Wrong PIN code entered!");
|
||||
MyEvents.SignalEvent("system.modem.wrongpingcode", NULL);
|
||||
MyNotify.NotifyStringf("alert", "modem.wrongpincode", "Wrong pin code (%s) entered!", MyConfig.GetParamValue("modem", "pincode"));
|
||||
MyNotify.NotifyStringf("alert", "modem.wrongpincode", "Wrong pin code (%s) entered!", pincode.c_str());
|
||||
MyConfig.SetParamValueBool("modem","wrongpincode",true);
|
||||
}
|
||||
else if (line.compare(0, 28, "+CME ERROR: SIM not inserted") == 0)
|
||||
{
|
||||
ESP_LOGE(TAG,"SIM not inserted!");
|
||||
MyEvents.SignalEvent("system.modem.simnotinserted", NULL);
|
||||
StandardMetrics.ms_m_net_mdm_iccid->SetValue(line.substr(12));
|
||||
}
|
||||
|
||||
// MMI/USSD response (URC):
|
||||
// sent on all free channels, so we only process m_mux_channel_CMD
|
||||
else if (channel == m_mux_channel_CMD && line.compare(0, 7, "+CUSD: ") == 0)
|
||||
// sent on all free channels or only on POLL, so we only process m_mux_channel_POLL
|
||||
else if (channel == m_mux_channel_POLL && line.compare(0, 7, "+CUSD: ") == 0)
|
||||
{
|
||||
// Format: +CUSD: 0,"…msg…",15
|
||||
// The message string may contain CR/LF so can come on multiple lines, with unknown length
|
||||
|
@ -1280,7 +1345,7 @@ void modem::StartTask()
|
|||
if (!m_task)
|
||||
{
|
||||
ESP_LOGV(TAG, "Starting modem task");
|
||||
xTaskCreatePinnedToCore(MODEM_task, "OVMS Cellular", CONFIG_OVMS_HW_CELLULAR_MODEM_STACK_SIZE, (void*)this, 20, &m_task, CORE(0));
|
||||
xTaskCreatePinnedToCore(MODEM_task, "OVMS Cellular", CONFIG_OVMS_HW_CELLULAR_MODEM_STACK_SIZE, (void*)this, 20, (void**)&m_task, CORE(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1298,27 +1363,42 @@ void modem::StopTask()
|
|||
}
|
||||
}
|
||||
|
||||
void modem::StartNMEA()
|
||||
bool modem::StartNMEA(bool force /*=false*/)
|
||||
{
|
||||
if ( (m_nmea == NULL) &&
|
||||
(MyConfig.GetParamValueBool("modem", "enable.gps", false)) )
|
||||
(force || MyConfig.GetParamValueBool("modem", "enable.gps", false)) )
|
||||
{
|
||||
ESP_LOGV(TAG, "Starting NMEA");
|
||||
m_nmea = new GsmNMEA(m_mux, m_mux_channel_NMEA, m_mux_channel_CMD);
|
||||
m_nmea->Startup();
|
||||
m_driver->StartupNMEA();
|
||||
if (!m_mux || !m_driver)
|
||||
{
|
||||
ESP_LOGE(TAG, "StartNMEA failed: MUX or driver not available");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGV(TAG, "Starting NMEA");
|
||||
m_nmea = new GsmNMEA(m_mux, m_mux_channel_NMEA, m_mux_channel_CMD);
|
||||
m_nmea->Startup();
|
||||
m_driver->StartupNMEA();
|
||||
}
|
||||
}
|
||||
return (m_nmea != NULL);
|
||||
}
|
||||
|
||||
void modem::StopNMEA()
|
||||
{
|
||||
if (m_nmea != NULL)
|
||||
{
|
||||
ESP_LOGV(TAG, "Stopping NMEA");
|
||||
m_driver->ShutdownNMEA();
|
||||
m_nmea->Shutdown();
|
||||
delete m_nmea;
|
||||
m_nmea = NULL;
|
||||
if (!m_mux || !m_driver)
|
||||
{
|
||||
ESP_LOGE(TAG, "StopNMEA failed: MUX or driver not available");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGV(TAG, "Stopping NMEA");
|
||||
m_driver->ShutdownNMEA();
|
||||
m_nmea->Shutdown();
|
||||
delete m_nmea;
|
||||
m_nmea = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1393,7 +1473,8 @@ void modem::Ticker(std::string event, void* data)
|
|||
|
||||
ev.event.type = TICKER1;
|
||||
|
||||
xQueueSend(m_queue,&ev,0);
|
||||
QueueHandle_t queue = m_queue;
|
||||
if (queue) xQueueSend(queue,&ev,0);
|
||||
}
|
||||
|
||||
void modem::EventListener(std::string event, void* data)
|
||||
|
@ -1421,17 +1502,7 @@ void modem::IncomingMuxData(GsmMuxChannel* channel)
|
|||
}
|
||||
else if (channel->m_channel == m_mux_channel_NMEA)
|
||||
{
|
||||
if (m_nmea != NULL)
|
||||
{
|
||||
while (channel->m_buffer.HasLine() >= 0)
|
||||
{
|
||||
m_nmea->IncomingLine(channel->m_buffer.ReadLine());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
channel->m_buffer.EmptyAll();
|
||||
}
|
||||
StandardIncomingHandler(channel->m_channel, &channel->m_buffer);
|
||||
}
|
||||
else if (channel->m_channel == m_mux_channel_DATA)
|
||||
{
|
||||
|
@ -1470,7 +1541,8 @@ void modem::SendSetState1(modem_state1_t newstate)
|
|||
ev.event.type = SETSTATE;
|
||||
ev.event.data.newstate = newstate;
|
||||
|
||||
xQueueSend(m_queue,&ev,0);
|
||||
QueueHandle_t queue = m_queue;
|
||||
if (queue) xQueueSend(queue,&ev,0);
|
||||
}
|
||||
|
||||
bool modem::IsStarted()
|
||||
|
@ -1478,14 +1550,25 @@ bool modem::IsStarted()
|
|||
return (m_task != NULL);
|
||||
}
|
||||
|
||||
void modem::SetNetworkRegistration(network_registration_t netreg)
|
||||
void modem::SetNetworkRegistration(network_regtype_t regtype, network_registration_t netreg)
|
||||
{
|
||||
if (netreg != m_netreg)
|
||||
if (netreg != m_netreg_d[regtype])
|
||||
{
|
||||
m_netreg = netreg;
|
||||
const char *v = ModemNetRegName(m_netreg);
|
||||
ESP_LOGI(TAG, "Network Registration status: %s", v);
|
||||
StdMetrics.ms_m_net_mdm_netreg->SetValue(v);
|
||||
m_netreg_d[regtype] = netreg;
|
||||
|
||||
// Need to re-calculate m_netreg as best of these
|
||||
network_registration_t highest = Unknown;
|
||||
for (size_t k=0; k<CELLULAR_NETREG_COUNT; k++)
|
||||
{
|
||||
if (highest < m_netreg_d[k]) highest = m_netreg_d[k];
|
||||
}
|
||||
if (highest != m_netreg)
|
||||
{
|
||||
m_netreg = highest;
|
||||
const char *v = ModemNetRegName(m_netreg);
|
||||
ESP_LOGI(TAG, "Network Registration status: %s", v);
|
||||
StdMetrics.ms_m_net_mdm_netreg->SetValue(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1525,6 +1608,7 @@ void modem::SetSignalQuality(int newsq)
|
|||
void modem::ClearNetMetrics()
|
||||
{
|
||||
m_netreg = Unknown;
|
||||
for (size_t k=0; k<CELLULAR_NETREG_COUNT; k++) { m_netreg_d[k] = Unknown; }
|
||||
StdMetrics.ms_m_net_mdm_netreg->Clear();
|
||||
|
||||
m_provider = "";
|
||||
|
@ -1587,6 +1671,10 @@ void cellular_muxtx(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int arg
|
|||
void cellular_cmd(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
|
||||
{
|
||||
std::string msg;
|
||||
|
||||
MyModem->m_cmd_output.clear();
|
||||
MyModem->m_cmd_running = true;
|
||||
|
||||
for (int k=0; k<argc; k++)
|
||||
{
|
||||
if (k>0)
|
||||
|
@ -1596,14 +1684,31 @@ void cellular_cmd(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc,
|
|||
msg.append(argv[k]);
|
||||
}
|
||||
msg.append("\r\n");
|
||||
bool sent = MyModem->txcmd(msg.c_str(),msg.length());
|
||||
if (!MyModem->txcmd(msg.c_str(),msg.length()))
|
||||
{
|
||||
if (verbosity >= COMMAND_RESULT_MINIMAL)
|
||||
{
|
||||
writer->puts("ERROR: MODEM command channel not available!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for output to stabilise
|
||||
size_t cmdsize = UINT_MAX;
|
||||
size_t iter = 0;
|
||||
while ((MyModem->m_cmd_output.size() != cmdsize) && (iter < 5))
|
||||
{
|
||||
iter++;
|
||||
cmdsize = MyModem->m_cmd_output.size();
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
}
|
||||
|
||||
MyModem->m_cmd_running = false;
|
||||
if (verbosity >= COMMAND_RESULT_MINIMAL)
|
||||
{
|
||||
if (sent)
|
||||
writer->puts("MODEM command has been sent.");
|
||||
else
|
||||
writer->puts("ERROR: MODEM command channel not available!");
|
||||
writer->write(MyModem->m_cmd_output.c_str(), MyModem->m_cmd_output.size());
|
||||
}
|
||||
MyModem->m_cmd_output.clear();
|
||||
}
|
||||
|
||||
void cellular_status(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
|
||||
|
@ -1636,6 +1741,53 @@ void modem_setstate(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int arg
|
|||
writer->printf("Error: Unrecognised state %s\n",statename);
|
||||
}
|
||||
|
||||
void modem_gps_status(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
|
||||
{
|
||||
writer->printf("GPS status: autostart %s, currently %s.\n",
|
||||
MyConfig.GetParamValueBool("modem", "enable.gps", false) ? "enabled" : "disabled",
|
||||
(MyModem && MyModem->m_nmea) ? "running" : "not running");
|
||||
}
|
||||
|
||||
void modem_gps_start(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
|
||||
{
|
||||
if (!MyModem || !MyModem->m_mux || !MyModem->m_mux->IsMuxUp())
|
||||
{
|
||||
writer->puts("ERROR: Modem not ready");
|
||||
return;
|
||||
}
|
||||
if (MyModem->m_nmea)
|
||||
{
|
||||
writer->puts("GPS already running.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (MyModem->StartNMEA(true))
|
||||
{
|
||||
writer->puts("GPS started (may take a minute to find satellites).");
|
||||
}
|
||||
else
|
||||
{
|
||||
writer->puts("ERROR: GPS startup failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void modem_gps_stop(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
|
||||
{
|
||||
if (!MyModem || !MyModem->m_mux || !MyModem->m_mux->IsMuxUp())
|
||||
{
|
||||
writer->puts("ERROR: Modem not ready");
|
||||
return;
|
||||
}
|
||||
if (!MyModem->m_nmea)
|
||||
{
|
||||
writer->puts("GPS already stopped.");
|
||||
return;
|
||||
}
|
||||
|
||||
MyModem->StopNMEA();
|
||||
writer->puts("GPS stopped.");
|
||||
}
|
||||
|
||||
void cellular_drivers(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
|
||||
{
|
||||
writer->puts("Type Name");
|
||||
|
@ -1691,6 +1843,11 @@ CellularModemInit::CellularModemInit()
|
|||
cmd_setstate->RegisterCommand(ModemState1Name((modem::modem_state1_t)x),"Force CELLULAR MODEM state change",modem_setstate);
|
||||
}
|
||||
|
||||
OvmsCommand* cmd_gps = cmd_cellular->RegisterCommand("gps", "GPS/GNSS state control", modem_gps_status);
|
||||
cmd_gps->RegisterCommand("status", "GPS/GNSS status", modem_gps_status);
|
||||
cmd_gps->RegisterCommand("start", "Start GPS/GNSS", modem_gps_start);
|
||||
cmd_gps->RegisterCommand("stop", "Stop GPS/GNSS", modem_gps_stop);
|
||||
|
||||
MyConfig.RegisterParam("modem", "Modem Configuration", true, true);
|
||||
// Our instances:
|
||||
// 'driver': Driver to use (default: auto)
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
#define CELLULAR_NETREG_COUNT 3
|
||||
|
||||
class modemdriver; // Forward declaration
|
||||
|
||||
class modem : public pcp, public InternalRamAllocated
|
||||
|
@ -56,7 +58,7 @@ class modem : public pcp, public InternalRamAllocated
|
|||
~modem();
|
||||
|
||||
protected:
|
||||
TaskHandle_t m_task;
|
||||
volatile TaskHandle_t m_task;
|
||||
volatile QueueHandle_t m_queue;
|
||||
int m_baud;
|
||||
int m_rxpin;
|
||||
|
@ -93,13 +95,23 @@ class modem : public pcp, public InternalRamAllocated
|
|||
} event_type_t;
|
||||
typedef enum
|
||||
{
|
||||
NotRegistered = 0,
|
||||
Searching = 2,
|
||||
DeniedRegistration = 3,
|
||||
RegisteredHome = 1,
|
||||
RegisteredRoaming = 5,
|
||||
Unknown = 99
|
||||
Unknown = 0,
|
||||
NotRegistered = 1,
|
||||
DeniedRegistration = 2,
|
||||
Searching = 3,
|
||||
Registered = 4,
|
||||
RegisteredEmergencyServices = 5,
|
||||
RegisteredRoamingSMS = 6,
|
||||
RegisteredRoaming = 7,
|
||||
RegisteredHomeSMS = 8,
|
||||
RegisteredHome = 9
|
||||
} network_registration_t;
|
||||
typedef enum
|
||||
{
|
||||
NRT_GSM = 0,
|
||||
NRT_GPRS = 1,
|
||||
NRT_EPS = 2
|
||||
} network_regtype_t;
|
||||
typedef struct
|
||||
{
|
||||
event_type_t type;
|
||||
|
@ -126,6 +138,7 @@ class modem : public pcp, public InternalRamAllocated
|
|||
|
||||
std::string m_line_buffer;
|
||||
network_registration_t m_netreg;
|
||||
network_registration_t m_netreg_d[CELLULAR_NETREG_COUNT];
|
||||
std::string m_provider;
|
||||
int m_sq;
|
||||
bool m_pincode_required;
|
||||
|
@ -150,6 +163,9 @@ class modem : public pcp, public InternalRamAllocated
|
|||
GsmPPPOS* m_ppp;
|
||||
GsmNMEA* m_nmea;
|
||||
|
||||
bool m_cmd_running;
|
||||
std::string m_cmd_output;
|
||||
|
||||
public:
|
||||
// Modem power control and initialisation
|
||||
virtual void SetPowerMode(PowerMode powermode);
|
||||
|
@ -185,7 +201,7 @@ class modem : public pcp, public InternalRamAllocated
|
|||
// High level API functions
|
||||
void StartTask();
|
||||
void StopTask();
|
||||
void StartNMEA();
|
||||
bool StartNMEA(bool force=false);
|
||||
void StopNMEA();
|
||||
void StartMux();
|
||||
void StopMux();
|
||||
|
@ -198,7 +214,7 @@ class modem : public pcp, public InternalRamAllocated
|
|||
void IncomingMuxData(GsmMuxChannel* channel);
|
||||
void SendSetState1(modem_state1_t newstate);
|
||||
bool IsStarted();
|
||||
void SetNetworkRegistration(network_registration_t netreg);
|
||||
void SetNetworkRegistration(network_regtype_t regtype, network_registration_t netreg);
|
||||
void SetProvider(std::string provider);
|
||||
void SetSignalQuality(int newsq);
|
||||
void ClearNetMetrics();
|
||||
|
@ -241,6 +257,7 @@ class modemdriver : public InternalRamAllocated
|
|||
protected:
|
||||
unsigned int m_powercyclefactor;
|
||||
modem* m_modem;
|
||||
int m_statuspoller_step;
|
||||
};
|
||||
|
||||
template<typename Type> modemdriver* CreateCellularModemDriver()
|
||||
|
|
|
@ -61,6 +61,7 @@ modemdriver::modemdriver()
|
|||
{
|
||||
m_modem = MyPeripherals->m_cellular_modem;
|
||||
m_powercyclefactor = 0;
|
||||
m_statuspoller_step = 0;
|
||||
}
|
||||
|
||||
modemdriver::~modemdriver()
|
||||
|
@ -81,9 +82,9 @@ void modemdriver::Restart()
|
|||
{
|
||||
ESP_LOGI(TAG, "Restart");
|
||||
if (MyConfig.GetParamValueBool("auto", "modem", false))
|
||||
m_modem->SetState1((m_modem->GetState1() != modem::PoweredOff) ? modem::PowerOffOn : modem::PoweringOn);
|
||||
m_modem->SendSetState1((m_modem->GetState1() != modem::PoweredOff) ? modem::PowerOffOn : modem::PoweringOn);
|
||||
else
|
||||
m_modem->SetState1(modem::PoweringOff);
|
||||
m_modem->SendSetState1(modem::PoweringOff);
|
||||
}
|
||||
|
||||
void modemdriver::PowerOff()
|
||||
|
@ -100,6 +101,7 @@ void modemdriver::PowerCycle()
|
|||
m_powercyclefactor = m_powercyclefactor % 3;
|
||||
ESP_LOGI(TAG, "Power Cycle %dms", psd);
|
||||
|
||||
uart_wait_tx_done(m_modem->m_uartnum, portMAX_DELAY);
|
||||
uart_flush(m_modem->m_uartnum); // Flush the ring buffer, to try to address MUX start issues
|
||||
#ifdef CONFIG_OVMS_COMP_MAX7317
|
||||
MyPeripherals->m_max7317->Output(MODEM_EGPIO_PWR, 0); // Modem EN/PWR line low
|
||||
|
@ -141,7 +143,12 @@ void modemdriver::ShutdownNMEA()
|
|||
{
|
||||
// Switch off GPS:
|
||||
if (m_modem->m_mux != NULL)
|
||||
{ m_modem->muxtx(GetMuxChannelCMD(), "AT+CGPS=0\r\n"); }
|
||||
{
|
||||
// send single commands, as each can fail:
|
||||
m_modem->muxtx(GetMuxChannelCMD(), "AT+CGPSNMEA=0\r\n");
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
m_modem->muxtx(GetMuxChannelCMD(), "AT+CGPS=0\r\n");
|
||||
}
|
||||
else
|
||||
{ ESP_LOGE(TAG, "Attempt to transmit on non running mux"); }
|
||||
}
|
||||
|
@ -154,11 +161,13 @@ void modemdriver::StatusPoller()
|
|||
|
||||
bool modemdriver::State1Leave(modem::modem_state1_t oldstate)
|
||||
{
|
||||
m_statuspoller_step = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool modemdriver::State1Enter(modem::modem_state1_t newstate)
|
||||
{
|
||||
m_statuspoller_step = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -169,5 +178,9 @@ modem::modem_state1_t modemdriver::State1Activity(modem::modem_state1_t curstate
|
|||
|
||||
modem::modem_state1_t modemdriver::State1Ticker1(modem::modem_state1_t curstate)
|
||||
{
|
||||
if (m_statuspoller_step > 0)
|
||||
{
|
||||
StatusPoller();
|
||||
}
|
||||
return curstate;
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ bool OvmsHttpClient::Request(std::string url, const char* method)
|
|||
{
|
||||
// ESP_LOGI(TAG, "Got response %s",m_buf->ReadLine().c_str());
|
||||
std::string header = m_buf->ReadLine();
|
||||
if (header.compare(0,15,"Content-Length:") == 0)
|
||||
if (strncasecmp(header.c_str(), "Content-Length:", 15) == 0)
|
||||
{
|
||||
m_bodysize = atoi(header.substr(15).c_str());
|
||||
}
|
||||
|
|
|
@ -290,9 +290,10 @@ void OvmsLocation::Store(std::string& buf)
|
|||
|
||||
void OvmsLocation::Render(std::string& buf)
|
||||
{
|
||||
char val[32];
|
||||
snprintf(val, sizeof(val), "%0.6f,%0.6f (%dm)", m_latitude, m_longitude, m_radius);
|
||||
buf = val;
|
||||
metric_unit_t user_length = OvmsMetricGetUserUnit(GrpDistanceShort, Meters);
|
||||
|
||||
buf = string_format("%0.6f,%0.6f (%d%s)",
|
||||
m_latitude, m_longitude, UnitConvert(Meters, user_length, m_radius), OvmsMetricUnitLabel(user_length));
|
||||
bool first = true;
|
||||
for (ActionList::iterator it = m_actions.begin(); it != m_actions.end(); ++it)
|
||||
{
|
||||
|
@ -369,11 +370,22 @@ void location_list(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc
|
|||
writer->puts("NOTE: ACC actions are not implemented yet!"); // XXX IMPLEMENT AND REMOVE THIS!
|
||||
}
|
||||
|
||||
int location_set_validate(OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv, bool complete)
|
||||
{
|
||||
if (argc == 5)
|
||||
{
|
||||
return OvmsMetricUnit_Validate(writer, argc, argv[4], complete, GrpDistanceShort);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void location_set(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
|
||||
{
|
||||
const char *name = argv[0];
|
||||
float latitude, longitude;
|
||||
int radius = LOCATION_DEFRADIUS;
|
||||
int base_value = radius;
|
||||
metric_unit_t user_length = Meters;
|
||||
|
||||
if (strcmp(name, "?") == 0)
|
||||
{
|
||||
|
@ -391,12 +403,37 @@ void location_set(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc,
|
|||
longitude = MyLocations.m_longitude;
|
||||
}
|
||||
|
||||
if (argc > 3) radius = atoi(argv[3]);
|
||||
if (argc > 3)
|
||||
{
|
||||
radius = atoi(argv[3]);
|
||||
base_value = radius;
|
||||
if (argc < 5)
|
||||
user_length = OvmsMetricGetUserUnit(GrpDistanceShort, Meters);
|
||||
else
|
||||
{
|
||||
user_length = OvmsMetricUnitFromName(argv[4]);
|
||||
if (user_length == UnitNotFound)
|
||||
{
|
||||
writer->printf("Error: Invalid Metric %s\n", argv[4]);
|
||||
return;
|
||||
}
|
||||
user_length = OvmsMetricCheckUnit(Meters, user_length);
|
||||
if (user_length == UnitNotFound)
|
||||
{
|
||||
writer->printf("Error: Metric %s is not a length unit\n", argv[4]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
char val[32];
|
||||
snprintf(val,sizeof(val),"%0.6f,%0.6f,%d",latitude,longitude,radius);
|
||||
MyConfig.SetParamValue(LOCATIONS_PARAM,name,val);
|
||||
writer->puts("Location defined");
|
||||
radius = UnitConvert(user_length, Meters, radius);
|
||||
}
|
||||
|
||||
std::string val = string_format("%0.6f,%0.6f,%d",latitude,longitude,radius);
|
||||
MyConfig.SetParamValue(LOCATIONS_PARAM,name,val.c_str());
|
||||
if (user_length == Meters)
|
||||
writer->printf("Location defined with radius of %dm\n", base_value);
|
||||
else
|
||||
writer->printf("Location defined with radius of %d%s = %dm\n", base_value, OvmsMetricUnitLabel(user_length), radius);
|
||||
}
|
||||
|
||||
void location_radius(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
|
||||
|
@ -409,12 +446,35 @@ void location_radius(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int ar
|
|||
writer->printf("Error: No location %s defined\n",name);
|
||||
return;
|
||||
}
|
||||
metric_unit_t user_length;
|
||||
if (argc < 3)
|
||||
user_length = OvmsMetricGetUserUnit(GrpDistanceShort, Meters);
|
||||
else
|
||||
{
|
||||
user_length = OvmsMetricUnitFromName(argv[2]);
|
||||
if (user_length == UnitNotFound)
|
||||
{
|
||||
writer->printf("Error: Invalid Metric %s\n", argv[2]);
|
||||
return;
|
||||
}
|
||||
user_length = OvmsMetricCheckUnit(Meters, user_length);
|
||||
if (user_length == UnitNotFound)
|
||||
{
|
||||
writer->printf("Error: Metric %s is not a length unit\n", argv[2]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::string buf;
|
||||
OvmsLocation* loc = *locp;
|
||||
loc->m_radius = atoi(argv[1]);
|
||||
int base_value = atoi(argv[1]);
|
||||
int radius_m = UnitConvert(user_length, Meters, base_value);
|
||||
loc->m_radius = radius_m;
|
||||
loc->Store(buf);
|
||||
writer->puts("Location radius set");
|
||||
if (user_length == Meters)
|
||||
writer->printf("Location radius set to %dm\n", base_value);
|
||||
else
|
||||
writer->printf("Location radius set to %d%s = %dm\n", base_value, OvmsMetricUnitLabel(user_length), radius_m);
|
||||
}
|
||||
|
||||
void location_rm(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
|
||||
|
@ -439,7 +499,10 @@ void location_status(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int ar
|
|||
writer->printf("(%sGPS lock", MyLocations.m_gpslock ? "" : "without ");
|
||||
n = StandardMetrics.ms_v_pos_satcount->AsInt();
|
||||
if (n > 0)
|
||||
writer->printf(", %d satellite%s", n, n == 1 ? "" : "s");
|
||||
{
|
||||
writer->printf(", %d satellite%s, %s", n, n == 1 ? "" : "s",
|
||||
MyLocations.m_gpsgood ? "reliable" : "unreliable");
|
||||
}
|
||||
writer->puts(")");
|
||||
|
||||
if ((MyLocations.m_park_latitude != 0) || (MyLocations.m_park_longitude != 0))
|
||||
|
@ -474,6 +537,16 @@ int location_validate(OvmsWriter* writer, OvmsCommand* cmd, int argc, const char
|
|||
return -1;
|
||||
}
|
||||
|
||||
int location_radius_validate(OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv, bool complete)
|
||||
{
|
||||
switch (argc)
|
||||
{
|
||||
case 1: return MyLocations.m_locations.Validate(writer, argc, argv[0], complete);
|
||||
case 3: return OvmsMetricUnit_Validate(writer, argc, argv[2], complete, GrpDistanceShort);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void location_action(int verbosity, OvmsWriter* writer, enum LocationAction act, std::string& params)
|
||||
{
|
||||
const char* const* rargv = writer->GetArgv();
|
||||
|
@ -618,6 +691,8 @@ OvmsLocations::OvmsLocations()
|
|||
|
||||
m_ready = false;
|
||||
m_gpslock = false;
|
||||
m_gpssq = 0;
|
||||
m_gpsgood = false;
|
||||
m_latitude = 0;
|
||||
m_longitude = 0;
|
||||
m_park_latitude = 0;
|
||||
|
@ -629,8 +704,8 @@ OvmsLocations::OvmsLocations()
|
|||
// Register our commands
|
||||
OvmsCommand* cmd_location = MyCommandApp.RegisterCommand("location","LOCATION framework", location_status, "", 0, 0, false);
|
||||
cmd_location->RegisterCommand("list","Show all locations",location_list);
|
||||
cmd_location->RegisterCommand("set","Set the position of a location",location_set, "<name> [<latitude> <longitude> [<radius>]]", 1, 4);
|
||||
cmd_location->RegisterCommand("radius","Set the radius of a location",location_radius, "<name> <radius>", 2, 2, true, location_validate);
|
||||
cmd_location->RegisterCommand("set","Set the position of a location",location_set, "<name> [<latitude> <longitude> [<radius> [<unit>]] ]", 1, 5, true, location_set_validate);
|
||||
cmd_location->RegisterCommand("radius","Set the radius of a location (defaults to user 'height' units)",location_radius, "<name> <radius> [<unit>]", 2, 3, true, location_radius_validate);
|
||||
cmd_location->RegisterCommand("rm","Remove a defined location",location_rm, "<name>", 1, 1, true, location_validate);
|
||||
cmd_location->RegisterCommand("status","Show location status",location_status);
|
||||
OvmsCommand* cmd_action = cmd_location->RegisterCommand("action","Set an action for a location");
|
||||
|
@ -671,8 +746,8 @@ OvmsLocations::OvmsLocations()
|
|||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
MyMetrics.RegisterListener(TAG, MS_V_POS_GPSLOCK, std::bind(&OvmsLocations::UpdatedGpsLock, this, _1));
|
||||
MyMetrics.RegisterListener(TAG, MS_V_POS_LATITUDE, std::bind(&OvmsLocations::UpdatedLatitude, this, _1));
|
||||
MyMetrics.RegisterListener(TAG, MS_V_POS_LONGITUDE, std::bind(&OvmsLocations::UpdatedLongitude, this, _1));
|
||||
MyMetrics.RegisterListener(TAG, MS_V_POS_GPSSQ, std::bind(&OvmsLocations::UpdatedGpsSQ, this, _1));
|
||||
MyMetrics.RegisterListener(TAG, MS_V_POS_GPSTIME, std::bind(&OvmsLocations::UpdatedPosition, this, _1));
|
||||
MyMetrics.RegisterListener(TAG, MS_V_ENV_ON, std::bind(&OvmsLocations::UpdatedVehicleOn, this, _1));
|
||||
MyEvents.RegisterEvent(TAG,"config.mounted", std::bind(&OvmsLocations::UpdatedConfig, this, _1, _2));
|
||||
MyEvents.RegisterEvent(TAG,"config.changed", std::bind(&OvmsLocations::UpdatedConfig, this, _1, _2));
|
||||
|
@ -696,12 +771,6 @@ void OvmsLocations::UpdatedGpsLock(OvmsMetric* metric)
|
|||
m_gpslock = m->AsBool();
|
||||
if (m_gpslock)
|
||||
{
|
||||
if (!m_ready)
|
||||
{
|
||||
UpdateParkPosition();
|
||||
m_ready = true;
|
||||
}
|
||||
UpdateLocations();
|
||||
MyEvents.SignalEvent("gps.lock.acquired", NULL);
|
||||
}
|
||||
else
|
||||
|
@ -710,22 +779,36 @@ void OvmsLocations::UpdatedGpsLock(OvmsMetric* metric)
|
|||
}
|
||||
}
|
||||
|
||||
void OvmsLocations::UpdatedLatitude(OvmsMetric* metric)
|
||||
void OvmsLocations::UpdatedGpsSQ(OvmsMetric* metric)
|
||||
{
|
||||
OvmsMetricFloat* m = (OvmsMetricFloat*)metric;
|
||||
m_latitude = m->AsFloat();
|
||||
if (m_gpslock)
|
||||
m_gpssq = StdMetrics.ms_v_pos_gpssq->AsInt();
|
||||
int level_good = MyConfig.GetParamValueInt("vehicle", "gps.sq.good", 60);
|
||||
int level_bad = MyConfig.GetParamValueInt("vehicle", "gps.sq.bad", 40);
|
||||
if (level_bad >= level_good) level_bad = level_good - 1;
|
||||
|
||||
if (!m_gpsgood && m_gpssq >= level_good)
|
||||
{
|
||||
m_gpsgood = true;
|
||||
if (!m_ready)
|
||||
{
|
||||
UpdateParkPosition();
|
||||
m_ready = true;
|
||||
}
|
||||
UpdateLocations();
|
||||
CheckTheft();
|
||||
MyEvents.SignalEvent("gps.sq.good", NULL);
|
||||
}
|
||||
else if (m_gpsgood && m_gpssq <= level_bad)
|
||||
{
|
||||
m_gpsgood = false;
|
||||
MyEvents.SignalEvent("gps.sq.bad", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void OvmsLocations::UpdatedLongitude(OvmsMetric* metric)
|
||||
void OvmsLocations::UpdatedPosition(OvmsMetric* metric)
|
||||
{
|
||||
OvmsMetricFloat* m = (OvmsMetricFloat*)metric;
|
||||
m_longitude = m->AsFloat();
|
||||
if (m_gpslock)
|
||||
m_latitude = StdMetrics.ms_v_pos_latitude->AsFloat();
|
||||
m_longitude = StdMetrics.ms_v_pos_longitude->AsFloat();
|
||||
if (m_gpsgood)
|
||||
{
|
||||
UpdateLocations();
|
||||
CheckTheft();
|
||||
|
@ -739,6 +822,8 @@ void OvmsLocations::UpdatedVehicleOn(OvmsMetric* metric)
|
|||
|
||||
void OvmsLocations::UpdateParkPosition()
|
||||
{
|
||||
OvmsRecMutexLock lock(&m_park_lock);
|
||||
|
||||
bool caron = StdMetrics.ms_v_env_on->AsBool();
|
||||
if (caron)
|
||||
{
|
||||
|
@ -753,13 +838,13 @@ void OvmsLocations::UpdateParkPosition()
|
|||
{
|
||||
m_park_latitude = m_latitude;
|
||||
m_park_longitude = m_longitude;
|
||||
m_park_invalid = (!m_gpslock || StdMetrics.ms_v_pos_latitude->IsStale() || StdMetrics.ms_v_pos_longitude->IsStale());
|
||||
m_park_invalid = (!m_gpsgood || StdMetrics.ms_v_pos_latitude->IsStale() || StdMetrics.ms_v_pos_longitude->IsStale());
|
||||
m_last_alarm = 0;
|
||||
ESP_LOGI(TAG, "UpdateParkPosition: vehicle is parking @%0.6f,%0.6f gpslock=%d satcount=%d hdop=%.1f invalid=%d",
|
||||
ESP_LOGI(TAG, "UpdateParkPosition: vehicle is parking @%0.6f,%0.6f gpslock=%d satcount=%d hdop=%.1f sq=%d invalid=%d",
|
||||
m_park_latitude, m_park_longitude, m_gpslock,
|
||||
StdMetrics.ms_v_pos_satcount->AsInt(),
|
||||
StdMetrics.ms_v_pos_gpshdop->AsFloat(),
|
||||
m_park_invalid);
|
||||
m_gpssq, m_park_invalid);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -813,7 +898,7 @@ void OvmsLocations::ReloadMap()
|
|||
}
|
||||
}
|
||||
|
||||
if (m_gpslock) UpdateLocations();
|
||||
if (m_gpsgood) UpdateLocations();
|
||||
}
|
||||
|
||||
void OvmsLocations::UpdateLocations()
|
||||
|
@ -830,6 +915,8 @@ void OvmsLocations::CheckTheft()
|
|||
{
|
||||
static int last_dist = 0;
|
||||
|
||||
OvmsRecMutexLock lock(&m_park_lock);
|
||||
|
||||
if ((m_park_latitude == 0) && (m_park_longitude == 0)) return;
|
||||
if (StandardMetrics.ms_v_env_on->AsBool()) return;
|
||||
|
||||
|
|
|
@ -96,12 +96,15 @@ class OvmsLocations
|
|||
public:
|
||||
bool m_ready;
|
||||
bool m_gpslock;
|
||||
int m_gpssq;
|
||||
bool m_gpsgood;
|
||||
float m_latitude;
|
||||
float m_longitude;
|
||||
float m_park_latitude;
|
||||
float m_park_longitude;
|
||||
float m_park_distance;
|
||||
bool m_park_invalid;
|
||||
OvmsRecMutex m_park_lock;
|
||||
uint32_t m_last_alarm;
|
||||
LocationMap m_locations;
|
||||
|
||||
|
@ -113,8 +116,8 @@ class OvmsLocations
|
|||
|
||||
public:
|
||||
void UpdatedGpsLock(OvmsMetric* metric);
|
||||
void UpdatedLatitude(OvmsMetric* metric);
|
||||
void UpdatedLongitude(OvmsMetric* metric);
|
||||
void UpdatedGpsSQ(OvmsMetric* metric);
|
||||
void UpdatedPosition(OvmsMetric* metric);
|
||||
void UpdatedVehicleOn(OvmsMetric* metric);
|
||||
void UpdatedConfig(std::string event, void* data);
|
||||
};
|
||||
|
|
|
@ -198,7 +198,7 @@ size_t OvmsNetHttpAsyncClient::IncomingData(void *data, size_t length)
|
|||
{
|
||||
// Process the header
|
||||
ESP_LOGD(TAG, "OvmsNetHttpAsyncClient Headers got %s", header.c_str());
|
||||
if (header.compare(0,15,"Content-Length:") == 0)
|
||||
if (strncasecmp(header.c_str(), "Content-Length:", 15) == 0)
|
||||
{
|
||||
m_bodysize = atoi(header.substr(15).c_str());
|
||||
ESP_LOGD(TAG, "OvmsNetHttpAsyncClient content-length is %d", m_bodysize);
|
||||
|
|
|
@ -38,7 +38,9 @@ static const char *TAG = "ota";
|
|||
#include <string.h>
|
||||
#include <esp_system.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#if ESP_IDF_VERSION_MAJOR < 4
|
||||
#include "strverscmp.h"
|
||||
#endif
|
||||
#include "ovms_ota.h"
|
||||
#include "ovms_command.h"
|
||||
#include "ovms_boot.h"
|
||||
|
@ -180,7 +182,7 @@ void ota_flash_vfs(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc
|
|||
writer->printf("Error: Cannot find file %s\n",argv[0]);
|
||||
return;
|
||||
}
|
||||
writer->printf("Source image is %d bytes in size\n",ds.st_size);
|
||||
writer->printf("Source image is %ld bytes in size\n",ds.st_size);
|
||||
|
||||
FILE* f = fopen(argv[0], "r");
|
||||
if (f == NULL)
|
||||
|
@ -242,7 +244,7 @@ void ota_flash_vfs(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc
|
|||
return;
|
||||
}
|
||||
|
||||
writer->printf("OTA flash was successful\n Flashed %d bytes from %s\n Next boot will be from '%s'\n",
|
||||
writer->printf("OTA flash was successful\n Flashed %ld bytes from %s\n Next boot will be from '%s'\n",
|
||||
ds.st_size,argv[0],target->label);
|
||||
MyConfig.SetParamValue("ota", "vfs.mru", argv[0]);
|
||||
}
|
||||
|
@ -931,7 +933,11 @@ static void OTAFlashTask(void *pvParameters)
|
|||
|
||||
if (fromsd)
|
||||
{
|
||||
#ifdef CONFIG_OVMS_COMP_SDCARD
|
||||
success = MyOTA.AutoFlashSD();
|
||||
#else
|
||||
success = false;
|
||||
#endif //CONFIG_OVMS_COMP_SDCARD
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -36,7 +36,10 @@ static const char *TAG = "pluginstore";
|
|||
#include <sys/stat.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include "esp_idf_version.h"
|
||||
#if ESP_IDF_VERSION_MAJOR < 4
|
||||
#include "strverscmp.h"
|
||||
#endif
|
||||
#include "ovms_plugins.h"
|
||||
#include "ovms_command.h"
|
||||
#include "ovms_config.h"
|
||||
|
|
|
@ -180,9 +180,9 @@ DuktapeHTTPRequest::DuktapeHTTPRequest(duk_context *ctx, int obj_idx)
|
|||
m_headers.append(": ");
|
||||
m_headers.append(val);
|
||||
m_headers.append("\r\n");
|
||||
if (key == "User-Agent")
|
||||
if (strcasecmp(key.c_str(), "User-Agent") == 0)
|
||||
have_useragent = true;
|
||||
else if (key == "Content-Type")
|
||||
else if (strcasecmp(key.c_str(), "Content-Type") == 0)
|
||||
have_contenttype = true;
|
||||
}
|
||||
duk_pop(ctx); // enum
|
||||
|
@ -325,7 +325,7 @@ void DuktapeHTTPRequest::MongooseCallback(struct mg_connection *nc, int ev, void
|
|||
key.assign(hm->header_names[i].p, hm->header_names[i].len);
|
||||
val.assign(hm->header_values[i].p, hm->header_values[i].len);
|
||||
m_response_headers.push_back(std::make_pair(key, val));
|
||||
if (key == "Location") location = val;
|
||||
if (strcasecmp(key.c_str(), "Location") == 0) location = val;
|
||||
}
|
||||
|
||||
// follow redirect?
|
||||
|
|
|
@ -1218,7 +1218,8 @@ void DukOvmsCommandRegisterRun(int verbosity, OvmsWriter* writer, OvmsCommand* c
|
|||
}
|
||||
else
|
||||
{
|
||||
DuktapeConsoleCommand* dcc = it->second;
|
||||
// TODO
|
||||
// DuktapeConsoleCommand* dcc = it->second;
|
||||
// Perform the callback
|
||||
}
|
||||
}
|
||||
|
|
|
@ -721,11 +721,11 @@ void OvmsServerV2::ProcessCommand(const char* payload)
|
|||
delete buffer;
|
||||
}
|
||||
|
||||
void OvmsServerV2::Transmit(const std::string& message)
|
||||
bool OvmsServerV2::Transmit(const std::string& message)
|
||||
{
|
||||
OvmsMutexLock mg(&m_mgconn_mutex);
|
||||
if (!m_mgconn)
|
||||
return;
|
||||
return false;
|
||||
|
||||
int len = message.length();
|
||||
char* s = new char[(len*2)+4];
|
||||
|
@ -775,6 +775,7 @@ void OvmsServerV2::Transmit(const std::string& message)
|
|||
|
||||
delete [] buf;
|
||||
delete [] s;
|
||||
return true;
|
||||
}
|
||||
|
||||
void OvmsServerV2::SetStatus(const char* status, bool fault, State newstate)
|
||||
|
@ -1181,6 +1182,7 @@ void OvmsServerV2::TransmitMsgGPS(bool always)
|
|||
StandardMetrics.ms_v_pos_direction->IsModifiedAndClear(MyOvmsServerV2Modifier) |
|
||||
StandardMetrics.ms_v_pos_altitude->IsModifiedAndClear(MyOvmsServerV2Modifier) |
|
||||
StandardMetrics.ms_v_pos_gpslock->IsModifiedAndClear(MyOvmsServerV2Modifier) |
|
||||
StandardMetrics.ms_v_pos_gpssq->IsModifiedAndClear(MyOvmsServerV2Modifier) |
|
||||
StandardMetrics.ms_v_pos_gpsmode->IsModifiedAndClear(MyOvmsServerV2Modifier) |
|
||||
StandardMetrics.ms_v_pos_gpshdop->IsModifiedAndClear(MyOvmsServerV2Modifier) |
|
||||
StandardMetrics.ms_v_pos_satcount->IsModifiedAndClear(MyOvmsServerV2Modifier) |
|
||||
|
@ -1197,10 +1199,7 @@ void OvmsServerV2::TransmitMsgGPS(bool always)
|
|||
if ((!always)&&(!modified)) return;
|
||||
|
||||
bool stale =
|
||||
StandardMetrics.ms_v_pos_latitude->IsStale() ||
|
||||
StandardMetrics.ms_v_pos_longitude->IsStale() ||
|
||||
StandardMetrics.ms_v_pos_direction->IsStale() ||
|
||||
StandardMetrics.ms_v_pos_altitude->IsStale();
|
||||
StandardMetrics.ms_v_pos_gpstime->IsStale();
|
||||
|
||||
char drivemode[10];
|
||||
sprintf(drivemode, "%x", StandardMetrics.ms_v_env_drivemode->AsInt());
|
||||
|
@ -1243,6 +1242,8 @@ void OvmsServerV2::TransmitMsgGPS(bool always)
|
|||
<< StandardMetrics.ms_v_pos_gpshdop->AsString("0", Native, 1)
|
||||
<< ","
|
||||
<< StandardMetrics.ms_v_pos_gpsspeed->AsString("0", units_speed, 1)
|
||||
<< ","
|
||||
<< StandardMetrics.ms_v_pos_gpssq->AsInt()
|
||||
;
|
||||
|
||||
Transmit(buffer.str().c_str());
|
||||
|
@ -1610,9 +1611,15 @@ void OvmsServerV2::TransmitNotifyInfo()
|
|||
buffer
|
||||
<< "MP-0 PI"
|
||||
<< mp_encode(e->GetValue());
|
||||
Transmit(buffer.str().c_str());
|
||||
|
||||
info->MarkRead(MyOvmsServerV2Reader, e);
|
||||
if (Transmit(buffer.str().c_str()))
|
||||
{
|
||||
info->MarkRead(MyOvmsServerV2Reader, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pending_notify_info = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1634,9 +1641,15 @@ void OvmsServerV2::TransmitNotifyError()
|
|||
buffer
|
||||
<< "MP-0 PE"
|
||||
<< e->GetValue(); // no mp_encode; payload structure "<vehicletype>,<errorcode>,<errordata>"
|
||||
Transmit(buffer.str().c_str());
|
||||
|
||||
alert->MarkRead(MyOvmsServerV2Reader, e);
|
||||
if (Transmit(buffer.str().c_str()))
|
||||
{
|
||||
alert->MarkRead(MyOvmsServerV2Reader, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pending_notify_error = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1658,9 +1671,15 @@ void OvmsServerV2::TransmitNotifyAlert()
|
|||
buffer
|
||||
<< "MP-0 PA"
|
||||
<< mp_encode(e->GetValue());
|
||||
Transmit(buffer.str().c_str());
|
||||
|
||||
alert->MarkRead(MyOvmsServerV2Reader, e);
|
||||
if (Transmit(buffer.str().c_str()))
|
||||
{
|
||||
alert->MarkRead(MyOvmsServerV2Reader, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pending_notify_alert = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1704,7 +1723,13 @@ void OvmsServerV2::TransmitNotifyData()
|
|||
<< -((int)(now - e->m_created) / 1000)
|
||||
<< ","
|
||||
<< msg;
|
||||
Transmit(buffer.str().c_str());
|
||||
if (!Transmit(buffer.str().c_str()))
|
||||
{
|
||||
m_pending_notify_data = true;
|
||||
m_pending_notify_data_last = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
m_pending_notify_data_last = e->m_id;
|
||||
|
||||
// be nice to other tasks, the network & the server:
|
||||
|
@ -1833,8 +1858,7 @@ bool OvmsServerV2::IncomingNotification(OvmsNotifyType* type, OvmsNotifyEntry* e
|
|||
buffer
|
||||
<< "MP-0 PI"
|
||||
<< mp_encode(entry->GetValue());
|
||||
Transmit(buffer.str().c_str());
|
||||
return true; // Mark it as read, as we've managed to send it
|
||||
return Transmit(buffer.str().c_str()); // Mark it as read if we've managed to send it
|
||||
}
|
||||
else if (strcmp(type->m_name,"error")==0)
|
||||
{
|
||||
|
@ -1848,8 +1872,7 @@ bool OvmsServerV2::IncomingNotification(OvmsNotifyType* type, OvmsNotifyEntry* e
|
|||
buffer
|
||||
<< "MP-0 PE"
|
||||
<< entry->GetValue(); // no mp_encode; payload structure "<vehicletype>,<errorcode>,<errordata>"
|
||||
Transmit(buffer.str().c_str());
|
||||
return true; // Mark it as read, as we've managed to send it
|
||||
return Transmit(buffer.str().c_str()); // Mark it as read if we've managed to send it
|
||||
}
|
||||
else if (strcmp(type->m_name,"alert")==0)
|
||||
{
|
||||
|
@ -1863,8 +1886,7 @@ bool OvmsServerV2::IncomingNotification(OvmsNotifyType* type, OvmsNotifyEntry* e
|
|||
buffer
|
||||
<< "MP-0 PA"
|
||||
<< mp_encode(entry->GetValue());
|
||||
Transmit(buffer.str().c_str());
|
||||
return true; // Mark it as read, as we've managed to send it
|
||||
return Transmit(buffer.str().c_str()); // Mark it as read if we've managed to send it
|
||||
}
|
||||
else if (strcmp(type->m_name,"data")==0)
|
||||
{
|
||||
|
@ -2172,8 +2194,13 @@ void ovmsv2_stop(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc,
|
|||
if (MyOvmsServerV2 != NULL)
|
||||
{
|
||||
writer->puts("Stopping OVMS Server V2 connection (oscv2)");
|
||||
delete MyOvmsServerV2;
|
||||
OvmsServerV2 *instance = MyOvmsServerV2;
|
||||
MyOvmsServerV2 = NULL;
|
||||
delete instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
writer->puts("OVMS v2 server has not been started");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ class OvmsServerV2 : public OvmsServer
|
|||
protected:
|
||||
void ProcessServerMsg();
|
||||
void ProcessCommand(const char* payload);
|
||||
void Transmit(const std::string& message);
|
||||
bool Transmit(const std::string& message);
|
||||
|
||||
protected:
|
||||
void TransmitMsgStat(bool always = false);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -979,6 +1162,7 @@ void ovmsv3_start(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc,
|
|||
{
|
||||
if (MyOvmsServerV3 == NULL)
|
||||
{
|
||||
writer->puts("Launching OVMS Server V3 connection (oscv3)");
|
||||
MyOvmsServerV3 = new OvmsServerV3("oscv3");
|
||||
}
|
||||
}
|
||||
|
@ -987,8 +1171,14 @@ void ovmsv3_stop(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc,
|
|||
{
|
||||
if (MyOvmsServerV3 != NULL)
|
||||
{
|
||||
delete MyOvmsServerV3;
|
||||
writer->puts("Stopping OVMS Server V3 connection (oscv3)");
|
||||
OvmsServerV3 *instance = MyOvmsServerV3;
|
||||
MyOvmsServerV3 = NULL;
|
||||
delete instance;
|
||||
}
|
||||
else
|
||||
{
|
||||
writer->puts("OVMS v3 server has not been started");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ void OvmsTLS::Reload()
|
|||
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;
|
||||
|
|
|
@ -140,8 +140,10 @@ void tpms_status(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc,
|
|||
|
||||
if (StandardMetrics.ms_v_tpms_pressure->IsDefined())
|
||||
{
|
||||
writer->printf("Pressure...[kPa]: ");
|
||||
for (auto val : StandardMetrics.ms_v_tpms_pressure->AsVector())
|
||||
|
||||
metric_unit_t user_pressure = OvmsMetricGetUserUnit(GrpPressure, kPa);
|
||||
writer->printf("Pressure...[%s]: ", OvmsMetricUnitLabel(user_pressure) );
|
||||
for (auto val : StandardMetrics.ms_v_tpms_pressure->AsVector(user_pressure))
|
||||
writer->printf(" %8.1f", val);
|
||||
writer->puts(StandardMetrics.ms_v_tpms_pressure->IsStale() ? " [stale]" : "");
|
||||
data_shown = true;
|
||||
|
@ -149,8 +151,9 @@ void tpms_status(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc,
|
|||
|
||||
if (StandardMetrics.ms_v_tpms_temp->IsDefined())
|
||||
{
|
||||
writer->printf("Temperature.[°C]: ");
|
||||
for (auto val : StandardMetrics.ms_v_tpms_temp->AsVector())
|
||||
metric_unit_t user_temp = OvmsMetricGetUserUnit(GrpTemp, Celcius);
|
||||
writer->printf("Temperature.[%s]: ", OvmsMetricUnitLabel(user_temp));
|
||||
for (auto val : StandardMetrics.ms_v_tpms_temp->AsVector(user_temp))
|
||||
writer->printf(" %8.1f", val);
|
||||
writer->puts(StandardMetrics.ms_v_tpms_temp->IsStale() ? " [stale]" : "");
|
||||
data_shown = true;
|
||||
|
|
|
@ -402,6 +402,180 @@ $.fn.loadcmd = function(command, filter, timeout) {
|
|||
var monitorTimer, last_monotonic = 0;
|
||||
var ws, ws_inhibit = 0;
|
||||
var metrics = {};
|
||||
var units = { metrics: {}, prefs: {} };
|
||||
|
||||
mi_to_km = function(mi) { return mi * 1.609347; }
|
||||
km_to_mi = function(km) { return km * 0.6213700; }
|
||||
pkm_to_pmi = function(pkm) { return pkm * 1.609347; }
|
||||
pmi_to_pkm = function(pmi) { return pmi * 0.6213700; }
|
||||
no_conversion = function (value) { return value;}
|
||||
x_to_kx = function (value) { return value/1000; }
|
||||
kx_to_x = function (value) { return value*1000; }
|
||||
|
||||
const feet_per_mile = 5280;
|
||||
|
||||
var unit_conversions = {
|
||||
"native": no_conversion,
|
||||
"km>miles": km_to_mi,
|
||||
"km>meters": kx_to_x,
|
||||
"km>feet": function (value) { return km_to_mi(value) * feet_per_mile; },
|
||||
"miles>km": mi_to_km,
|
||||
"miles>meters": function (value) { return (mi_to_km(value)*1000); },
|
||||
"miles>feet": function (value) { return value * feet_per_mile; },
|
||||
"meters>miles": function (value) { return km_to_mi(value/1000); },
|
||||
"meters>km": x_to_kx,
|
||||
"meters>feet": function (value) { return km_to_mi(value/1000) * feet_per_mile; },
|
||||
"feet>km": function (value) { return mi_to_km(value/feet_per_mile); },
|
||||
"feet>meters": function (value) { return (mi_to_km(value/feet_per_mile)*1000); },
|
||||
"feet>miles": function (value) { return value / feet_per_mile; },
|
||||
"kmphps>miphps": km_to_mi,
|
||||
"kmphps>mpss": function (value) { return value/3.6; },
|
||||
"kmphps>ftpss": function (value) { return km_to_mi(value)*feet_per_mile/3600; },
|
||||
"miphps>kmphps": mi_to_km,
|
||||
"miphps>mpss": function (value) { return mi_to_km(value)/3.6; },
|
||||
"miphps>ftpss": function (value) { return value*feet_per_mile/3600; },
|
||||
"mpss>kmphps": function (value) { return (value*3.6); },
|
||||
"mpss>miphps": function (value) { return km_to_mi(value)*3.6; },
|
||||
"mpss>ftpss": function (value) { return km_to_mi(value)*feet_per_mile; },
|
||||
"ftpss>kmphps": function (value) { return (mi_to_km(value/feet_per_mile)*3.6); },
|
||||
"ftpss>miphps": function (value) { return value *3600/feet_per_mile; },
|
||||
"ftpss>mpss": function (value) { return mi_to_km(value/feet_per_mile)*1000; },
|
||||
"kw>watts": kx_to_x,
|
||||
"watts>kw": x_to_kx,
|
||||
"kwh>watthours": kx_to_x,
|
||||
"watthours>kwh": x_to_kx,
|
||||
"whpkm>whpmi": pkm_to_pmi,
|
||||
"whpkm>kwhp100km": function (value) { return value / 10; },
|
||||
"whpkm>kmpkwh": function (value) { return value ? 1000.0 / value : 0; },
|
||||
"whpkm>mipkwh": function (value) { return value ? (km_to_mi(1000.0 / value)) : 0; },
|
||||
"whpmi>whpkm": pmi_to_pkm,
|
||||
"whpmi>kwhp100km": function (value) { return pmi_to_pkm(value) / 10; },
|
||||
"whpmi>kmpkwh": function (value) { return value ? (mi_to_km(1000.0 / value)) : 0; },
|
||||
"whpmi>mipkwh": function (value) { return value ? (1000.0 / value) : 0; },
|
||||
"kwhp100km>whpmi": function (value) { return pkm_to_pmi(value * 10); },
|
||||
"kwhp100km>whpkm": function (value) { return value * 10; },
|
||||
"kwhp100km>kmpkwh": function (value) { return value ? (100.0 / value) : 0; },
|
||||
"kwhp100km>mipkwh": function (value) { return value ? km_to_mi(100.0 / value) : 0; },
|
||||
"kmpkwh>whpmi": function (value) { return value ? (1000.0 / km_to_mi(value)) : 0;},
|
||||
"kmpkwh>whpkm": function (value) { return value ? (1/(1000.0 * value)) : 0;},
|
||||
"kmpkwh>kwhp100km": function (value) { return value ? (100.0/value) : 0;},
|
||||
"kmpkwh>mipkwh": km_to_mi,
|
||||
"mipkwh>whpmi": function (value) { return value ? 1000/value : 0;},
|
||||
"mipkwh>whpkm": function (value) { return value ? (1000 / mi_to_km(value)) : 0;},
|
||||
"mipkwh>kwhp100km": function (value) { return value ? (100.0/mi_to_km(value)) : 0;},
|
||||
"mipkwh>kmpkwh": mi_to_km,
|
||||
"celcius>fahrenheit": function (value) { return ((value*9)/5) + 32; },
|
||||
"fahrenheit>celcius": function (value) { return ((value-32)*5)/9; },
|
||||
"kpa>pa": kx_to_x,
|
||||
"kpa>bar": function (value) { return value/100; },
|
||||
"kpa>psi": function (value) { return value * 0.14503773773020923; },
|
||||
"pa>kpa": x_to_kx,
|
||||
"pa>bar": function (value) { return value/100000; },
|
||||
"pa>psi": function (value) { return value * 0.00014503773773020923; },
|
||||
"psi>kpa": function (value) { return value * 6.894757293168361; },
|
||||
"psi>pa": function (value) { return value * 6894.757293168361; },
|
||||
"psi>bar": function (value) { return value * 0.06894757293168361; },
|
||||
"bar>pa": function (value) { return value*100000; },
|
||||
"bar>kpa": function (value) { return value*100; },
|
||||
"bar>psi": function (value) { return value * 14.503773773020923; },
|
||||
"seconds>minutes": function (value) { return value/60; },
|
||||
"seconds>hours": function (value) { return value/3600; },
|
||||
"minutes>seconds": function (value) { return value*60; },
|
||||
"minutes>hours": function (value) { return value/60; },
|
||||
"hours>seconds": function (value) { return value*3600; },
|
||||
"hours>minutes": function (value) { return value*60; },
|
||||
"kmph>miph": km_to_mi,
|
||||
"miph>kmph": mi_to_km,
|
||||
"dbm>sq": function (value) { return Math.round((value <= -51) ? ((value + 113)/2) : 0); },
|
||||
"sq>dbm": function (value) { return Math.round((value <= 31) ? (-113 + (value*2)) : 0); },
|
||||
"percent>permille": function (value) { return value*10.0; },
|
||||
"permille>percent": function (value) { return value*0.10; }
|
||||
}
|
||||
convertUnitFunction = function (from, to) {
|
||||
return unit_conversions[from + ">" + to] || no_conversion;
|
||||
}
|
||||
convertUnits = function (from, to, value) {
|
||||
return convertUnitFunction(from, to)(value);
|
||||
}
|
||||
|
||||
units.convertMetricToUserUnits = function (value, name) {
|
||||
if (value == undefined)
|
||||
return value
|
||||
var unit_entry = this.metrics[name];
|
||||
if (unit_entry == undefined)
|
||||
return value
|
||||
var cnvfn = unit_entry.user_fn;
|
||||
if (cnvfn == undefined) {
|
||||
cnvfn = convertUnitFunction(unit_entry.native, unit_entry.code);
|
||||
this.metrics[name].user_fn = cnvfn;
|
||||
}
|
||||
return cnvfn(value);
|
||||
}
|
||||
units.userUnitLabelFromMetric = function (name) {
|
||||
var unit_entry = this.metrics[name];
|
||||
if (unit_entry == undefined)
|
||||
return "";
|
||||
return unit_entry.label;
|
||||
}
|
||||
units.unitLabelToUser = function (unitType, defaultLabel) {
|
||||
var res = this.prefs[unitType];
|
||||
return (res && res.label) ? res.label : defaultLabel
|
||||
}
|
||||
units.unitValueToUser = function (unitType, value) {
|
||||
var entry = this.prefs[unitType];
|
||||
if (!entry)
|
||||
return value;
|
||||
return convertUnits(value, unitType, entry.unit);
|
||||
}
|
||||
|
||||
// Works for units and metrics collection.
|
||||
metricsProxyHas = function(target, name) {
|
||||
return target[name] != undefined
|
||||
}
|
||||
|
||||
var metrics_all = new Proxy(metrics, {
|
||||
get: function(target, name) {
|
||||
if (name == Symbol.toStringTag)
|
||||
return 'metrics_all[]';
|
||||
if (!(typeof name === "string" || name instanceof String))
|
||||
return undefined;
|
||||
var names = name.split('#',2);
|
||||
var name = names[0];
|
||||
var value_type = names[1]
|
||||
if (value_type === "unit")
|
||||
return units.userUnitLabelFromMetric(name);
|
||||
var value = target[name];
|
||||
if (value_type === "label")
|
||||
value = units.convertMetricToUserUnits(value, name)
|
||||
return value;
|
||||
},
|
||||
has: metricsProxyHas
|
||||
});
|
||||
|
||||
var metrics_user = new Proxy(metrics, {
|
||||
get:
|
||||
function(target, name) {
|
||||
if (name == Symbol.toStringTag)
|
||||
return 'metrics_user[]';
|
||||
return units.convertMetricToUserUnits(target[name], name)
|
||||
},
|
||||
has: metricsProxyHas
|
||||
});
|
||||
|
||||
var metrics_label = new Proxy(units.metrics, {
|
||||
get:
|
||||
function(target, name) {
|
||||
if (name == Symbol.toStringTag)
|
||||
return 'metrics_label[]';
|
||||
var unit_entry = target[name];
|
||||
if (unit_entry == undefined) {
|
||||
return "";
|
||||
}
|
||||
return unit_entry.label;
|
||||
},
|
||||
has: metricsProxyHas
|
||||
});
|
||||
|
||||
var shellhist = [""], shellhpos = 0;
|
||||
var loghist = [];
|
||||
const loghist_maxsize = 100;
|
||||
|
@ -415,6 +589,7 @@ function initSocketConnection(){
|
|||
ws.onopen = function(ev) {
|
||||
console.log("WebSocket OPENED", ev);
|
||||
$(".receiver").subscribe();
|
||||
subscribeToTopic("units/#");
|
||||
};
|
||||
ws.onerror = function(ev) { console.log("WebSocket ERROR", ev); };
|
||||
ws.onclose = function(ev) { console.log("WebSocket CLOSED", ev); };
|
||||
|
@ -443,6 +618,21 @@ function initSocketConnection(){
|
|||
$.extend(metrics, msg.metrics);
|
||||
$(".receiver").trigger("msg:metrics", msg.metrics);
|
||||
}
|
||||
else if (msgtype == "units") {
|
||||
for (var subtype in msg.units) {
|
||||
if (subtype == "metrics") {
|
||||
$.extend(units.metrics, msg.units.metrics);
|
||||
$(".receiver").trigger("msg:units:metrics", msg.units.metrics);
|
||||
var msgmetrics = {};
|
||||
for (metricname in msg.units.metrics)
|
||||
msgmetrics[metricname] = metrics[metricname];
|
||||
$(".receiver").trigger("msg:metrics", msgmetrics);
|
||||
} else if (subtype == "prefs") {
|
||||
$.extend(units.prefs, msg.units.prefs);
|
||||
$(".receiver").trigger("msg:units:prefs", msg.units.prefs);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (msgtype == "notify") {
|
||||
processNotification(msg.notify);
|
||||
$(".receiver").trigger("msg:notify", msg.notify);
|
||||
|
@ -513,7 +703,14 @@ function processNotification(msg) {
|
|||
confirmdialog(opts.title, opts.body, ["OK"], opts.timeout);
|
||||
}
|
||||
|
||||
|
||||
subscribeToTopic = function (topic) {
|
||||
try {
|
||||
console.debug("subscribe " + topic);
|
||||
if (ws) ws.send("subscribe " + topic);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
$.fn.subscribe = function(topics) {
|
||||
return this.each(function() {
|
||||
var subscriptions = $(this).data("subscriptions");
|
||||
|
@ -526,13 +723,7 @@ $.fn.subscribe = function(topics) {
|
|||
var tops = topics ? topics.split(' ') : [];
|
||||
for (var i = 0; i < tops.length; i++) {
|
||||
if (tops[i] && !subs.includes(tops[i])) {
|
||||
try {
|
||||
console.log("subscribe " + tops[i]);
|
||||
if (ws) ws.send("subscribe " + tops[i]);
|
||||
subs.push(tops[i]);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
subscribeToTopic(tops[i]);
|
||||
}
|
||||
}
|
||||
$(this).data("subscriptions", subs.join(' '));
|
||||
|
@ -1721,20 +1912,43 @@ $(function(){
|
|||
// Metrics displays:
|
||||
$("body").on('msg:metrics', '.receiver', function(e, update) {
|
||||
$(this).find(".metric").each(function() {
|
||||
var $el = $(this), metric = $el.data("metric"), prec = $el.data("prec"), scale = $el.data("scale");
|
||||
var $el = $(this), metric = $el.data("metric"), prec = $el.data("prec"), scale = $el.data("scale"), useUser = $el.data("user");
|
||||
if (!metric) return;
|
||||
// filter:
|
||||
var keys = metric.split(","), val;
|
||||
var metricName = "";
|
||||
for (var i=0; i<keys.length; i++) {
|
||||
if ((val = update[keys[i]]) != null) break;
|
||||
metricName = keys[i];
|
||||
if ((val = update[metricName]) != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (val == null) return;
|
||||
|
||||
// process:
|
||||
if ($el.hasClass("text")) {
|
||||
$el.children(".value").text(val);
|
||||
var elt = $el.children(".value");
|
||||
if (elt) elt.text(val);
|
||||
elt = $el.children(".unit");
|
||||
if (elt) elt.text(val);
|
||||
|
||||
} else if ($el.hasClass("number")) {
|
||||
var vf = val;
|
||||
if (scale != null) vf = Number(vf) * scale;
|
||||
if (scale != null)
|
||||
vf = Number(vf) * scale;
|
||||
else {
|
||||
var mun = units.userUnitLabelFromMetric(metricName);
|
||||
if (mun != "") {
|
||||
// If there's a .unit.. then convert it.
|
||||
item = $el.children(".unit");
|
||||
if (item) {
|
||||
item.text(mun);
|
||||
useUser = true;
|
||||
}
|
||||
}
|
||||
if (useUser)
|
||||
vf = units.convertMetricToUserUnits(vf, metricName);
|
||||
}
|
||||
if (prec != null) vf = Number(vf).toFixed(prec);
|
||||
$el.children(".value").text(vf);
|
||||
} else if ($el.hasClass("progress")) {
|
||||
|
|
|
@ -829,6 +829,180 @@ $.fn.loadcmd = function(command, filter, timeout) {
|
|||
var monitorTimer, last_monotonic = 0;
|
||||
var ws, ws_inhibit = 0;
|
||||
var metrics = {};
|
||||
var units = { metrics: {}, prefs: {} };
|
||||
|
||||
mi_to_km = function(mi) { return mi * 1.609347; }
|
||||
km_to_mi = function(km) { return km * 0.6213700; }
|
||||
pkm_to_pmi = function(pkm) { return pkm * 1.609347; }
|
||||
pmi_to_pkm = function(pmi) { return pmi * 0.6213700; }
|
||||
no_conversion = function (value) { return value;}
|
||||
x_to_kx = function (value) { return value/1000; }
|
||||
kx_to_x = function (value) { return value*1000; }
|
||||
|
||||
const feet_per_mile = 5280;
|
||||
|
||||
var unit_conversions = {
|
||||
"native": no_conversion,
|
||||
"km>miles": km_to_mi,
|
||||
"km>meters": kx_to_x,
|
||||
"km>feet": function (value) { return km_to_mi(value) * feet_per_mile; },
|
||||
"miles>km": mi_to_km,
|
||||
"miles>meters": function (value) { return (mi_to_km(value)*1000); },
|
||||
"miles>feet": function (value) { return value * feet_per_mile; },
|
||||
"meters>miles": function (value) { return km_to_mi(value/1000); },
|
||||
"meters>km": x_to_kx,
|
||||
"meters>feet": function (value) { return km_to_mi(value/1000) * feet_per_mile; },
|
||||
"feet>km": function (value) { return mi_to_km(value/feet_per_mile); },
|
||||
"feet>meters": function (value) { return (mi_to_km(value/feet_per_mile)*1000); },
|
||||
"feet>miles": function (value) { return value / feet_per_mile; },
|
||||
"kmphps>miphps": km_to_mi,
|
||||
"kmphps>mpss": function (value) { return value/3.6; },
|
||||
"kmphps>ftpss": function (value) { return km_to_mi(value)*feet_per_mile/3600; },
|
||||
"miphps>kmphps": mi_to_km,
|
||||
"miphps>mpss": function (value) { return mi_to_km(value)/3.6; },
|
||||
"miphps>ftpss": function (value) { return value*feet_per_mile/3600; },
|
||||
"mpss>kmphps": function (value) { return (value*3.6); },
|
||||
"mpss>miphps": function (value) { return km_to_mi(value)*3.6; },
|
||||
"mpss>ftpss": function (value) { return km_to_mi(value)*feet_per_mile; },
|
||||
"ftpss>kmphps": function (value) { return (mi_to_km(value/feet_per_mile)*3.6); },
|
||||
"ftpss>miphps": function (value) { return value *3600/feet_per_mile; },
|
||||
"ftpss>mpss": function (value) { return mi_to_km(value/feet_per_mile)*1000; },
|
||||
"kw>watts": kx_to_x,
|
||||
"watts>kw": x_to_kx,
|
||||
"kwh>watthours": kx_to_x,
|
||||
"watthours>kwh": x_to_kx,
|
||||
"whpkm>whpmi": pkm_to_pmi,
|
||||
"whpkm>kwhp100km": function (value) { return value / 10; },
|
||||
"whpkm>kmpkwh": function (value) { return value ? 1000.0 / value : 0; },
|
||||
"whpkm>mipkwh": function (value) { return value ? (km_to_mi(1000.0 / value)) : 0; },
|
||||
"whpmi>whpkm": pmi_to_pkm,
|
||||
"whpmi>kwhp100km": function (value) { return pmi_to_pkm(value) / 10; },
|
||||
"whpmi>kmpkwh": function (value) { return value ? (mi_to_km(1000.0 / value)) : 0; },
|
||||
"whpmi>mipkwh": function (value) { return value ? (1000.0 / value) : 0; },
|
||||
"kwhp100km>whpmi": function (value) { return pkm_to_pmi(value * 10); },
|
||||
"kwhp100km>whpkm": function (value) { return value * 10; },
|
||||
"kwhp100km>kmpkwh": function (value) { return value ? (100.0 / value) : 0; },
|
||||
"kwhp100km>mipkwh": function (value) { return value ? km_to_mi(100.0 / value) : 0; },
|
||||
"kmpkwh>whpmi": function (value) { return value ? (1000.0 / km_to_mi(value)) : 0;},
|
||||
"kmpkwh>whpkm": function (value) { return value ? (1/(1000.0 * value)) : 0;},
|
||||
"kmpkwh>kwhp100km": function (value) { return value ? (100.0/value) : 0;},
|
||||
"kmpkwh>mipkwh": km_to_mi,
|
||||
"mipkwh>whpmi": function (value) { return value ? 1000/value : 0;},
|
||||
"mipkwh>whpkm": function (value) { return value ? (1000 / mi_to_km(value)) : 0;},
|
||||
"mipkwh>kwhp100km": function (value) { return value ? (100.0/mi_to_km(value)) : 0;},
|
||||
"mipkwh>kmpkwh": mi_to_km,
|
||||
"celcius>fahrenheit": function (value) { return ((value*9)/5) + 32; },
|
||||
"fahrenheit>celcius": function (value) { return ((value-32)*5)/9; },
|
||||
"kpa>pa": kx_to_x,
|
||||
"kpa>bar": function (value) { return value/100; },
|
||||
"kpa>psi": function (value) { return value * 0.14503773773020923; },
|
||||
"pa>kpa": x_to_kx,
|
||||
"pa>bar": function (value) { return value/100000; },
|
||||
"pa>psi": function (value) { return value * 0.00014503773773020923; },
|
||||
"psi>kpa": function (value) { return value * 6.894757293168361; },
|
||||
"psi>pa": function (value) { return value * 6894.757293168361; },
|
||||
"psi>bar": function (value) { return value * 0.06894757293168361; },
|
||||
"bar>pa": function (value) { return value*100000; },
|
||||
"bar>kpa": function (value) { return value*100; },
|
||||
"bar>psi": function (value) { return value * 14.503773773020923; },
|
||||
"seconds>minutes": function (value) { return value/60; },
|
||||
"seconds>hours": function (value) { return value/3600; },
|
||||
"minutes>seconds": function (value) { return value*60; },
|
||||
"minutes>hours": function (value) { return value/60; },
|
||||
"hours>seconds": function (value) { return value*3600; },
|
||||
"hours>minutes": function (value) { return value*60; },
|
||||
"kmph>miph": km_to_mi,
|
||||
"miph>kmph": mi_to_km,
|
||||
"dbm>sq": function (value) { return Math.round((value <= -51) ? ((value + 113)/2) : 0); },
|
||||
"sq>dbm": function (value) { return Math.round((value <= 31) ? (-113 + (value*2)) : 0); },
|
||||
"percent>permille": function (value) { return value*10.0; },
|
||||
"permille>percent": function (value) { return value*0.10; }
|
||||
}
|
||||
convertUnitFunction = function (from, to) {
|
||||
return unit_conversions[from + ">" + to] || no_conversion;
|
||||
}
|
||||
convertUnits = function (from, to, value) {
|
||||
return convertUnitFunction(from, to)(value);
|
||||
}
|
||||
|
||||
units.convertMetricToUserUnits = function (value, name) {
|
||||
if (value == undefined)
|
||||
return value
|
||||
var unit_entry = this.metrics[name];
|
||||
if (unit_entry == undefined)
|
||||
return value
|
||||
var cnvfn = unit_entry.user_fn;
|
||||
if (cnvfn == undefined) {
|
||||
cnvfn = convertUnitFunction(unit_entry.native, unit_entry.code);
|
||||
this.metrics[name].user_fn = cnvfn;
|
||||
}
|
||||
return cnvfn(value);
|
||||
}
|
||||
units.userUnitLabelFromMetric = function (name) {
|
||||
var unit_entry = this.metrics[name];
|
||||
if (unit_entry == undefined)
|
||||
return "";
|
||||
return unit_entry.label;
|
||||
}
|
||||
units.unitLabelToUser = function (unitType, defaultLabel) {
|
||||
var res = this.prefs[unitType];
|
||||
return (res && res.label) ? res.label : defaultLabel
|
||||
}
|
||||
units.unitValueToUser = function (unitType, value) {
|
||||
var entry = this.prefs[unitType];
|
||||
if (!entry)
|
||||
return value;
|
||||
return convertUnits(value, unitType, entry.unit);
|
||||
}
|
||||
|
||||
// Works for units and metrics collection.
|
||||
metricsProxyHas = function(target, name) {
|
||||
return target[name] != undefined
|
||||
}
|
||||
|
||||
var metrics_all = new Proxy(metrics, {
|
||||
get: function(target, name) {
|
||||
if (name == Symbol.toStringTag)
|
||||
return 'metrics_all[]';
|
||||
if (!(typeof name === "string" || name instanceof String))
|
||||
return undefined;
|
||||
var names = name.split('#',2);
|
||||
var name = names[0];
|
||||
var value_type = names[1]
|
||||
if (value_type === "unit")
|
||||
return units.userUnitLabelFromMetric(name);
|
||||
var value = target[name];
|
||||
if (value_type === "label")
|
||||
value = units.convertMetricToUserUnits(value, name)
|
||||
return value;
|
||||
},
|
||||
has: metricsProxyHas
|
||||
});
|
||||
|
||||
var metrics_user = new Proxy(metrics, {
|
||||
get:
|
||||
function(target, name) {
|
||||
if (name == Symbol.toStringTag)
|
||||
return 'metrics_user[]';
|
||||
return units.convertMetricToUserUnits(target[name], name)
|
||||
},
|
||||
has: metricsProxyHas
|
||||
});
|
||||
|
||||
var metrics_label = new Proxy(units.metrics, {
|
||||
get:
|
||||
function(target, name) {
|
||||
if (name == Symbol.toStringTag)
|
||||
return 'metrics_label[]';
|
||||
var unit_entry = target[name];
|
||||
if (unit_entry == undefined) {
|
||||
return "";
|
||||
}
|
||||
return unit_entry.label;
|
||||
},
|
||||
has: metricsProxyHas
|
||||
});
|
||||
|
||||
var shellhist = [""], shellhpos = 0;
|
||||
var loghist = [];
|
||||
const loghist_maxsize = 100;
|
||||
|
@ -842,6 +1016,7 @@ function initSocketConnection(){
|
|||
ws.onopen = function(ev) {
|
||||
console.log("WebSocket OPENED", ev);
|
||||
$(".receiver").subscribe();
|
||||
subscribeToTopic("units/#");
|
||||
};
|
||||
ws.onerror = function(ev) { console.log("WebSocket ERROR", ev); };
|
||||
ws.onclose = function(ev) { console.log("WebSocket CLOSED", ev); };
|
||||
|
@ -870,6 +1045,21 @@ function initSocketConnection(){
|
|||
$.extend(metrics, msg.metrics);
|
||||
$(".receiver").trigger("msg:metrics", msg.metrics);
|
||||
}
|
||||
else if (msgtype == "units") {
|
||||
for (var subtype in msg.units) {
|
||||
if (subtype == "metrics") {
|
||||
$.extend(units.metrics, msg.units.metrics);
|
||||
$(".receiver").trigger("msg:units:metrics", msg.units.metrics);
|
||||
var msgmetrics = {};
|
||||
for (metricname in msg.units.metrics)
|
||||
msgmetrics[metricname] = metrics[metricname];
|
||||
$(".receiver").trigger("msg:metrics", msgmetrics);
|
||||
} else if (subtype == "prefs") {
|
||||
$.extend(units.prefs, msg.units.prefs);
|
||||
$(".receiver").trigger("msg:units:prefs", msg.units.prefs);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (msgtype == "notify") {
|
||||
processNotification(msg.notify);
|
||||
$(".receiver").trigger("msg:notify", msg.notify);
|
||||
|
@ -940,7 +1130,14 @@ function processNotification(msg) {
|
|||
confirmdialog(opts.title, opts.body, ["OK"], opts.timeout);
|
||||
}
|
||||
|
||||
|
||||
subscribeToTopic = function (topic) {
|
||||
try {
|
||||
console.debug("subscribe " + topic);
|
||||
if (ws) ws.send("subscribe " + topic);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
$.fn.subscribe = function(topics) {
|
||||
return this.each(function() {
|
||||
var subscriptions = $(this).data("subscriptions");
|
||||
|
@ -953,13 +1150,7 @@ $.fn.subscribe = function(topics) {
|
|||
var tops = topics ? topics.split(' ') : [];
|
||||
for (var i = 0; i < tops.length; i++) {
|
||||
if (tops[i] && !subs.includes(tops[i])) {
|
||||
try {
|
||||
console.log("subscribe " + tops[i]);
|
||||
if (ws) ws.send("subscribe " + tops[i]);
|
||||
subs.push(tops[i]);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
subscribeToTopic(tops[i]);
|
||||
}
|
||||
}
|
||||
$(this).data("subscriptions", subs.join(' '));
|
||||
|
@ -2148,20 +2339,43 @@ $(function(){
|
|||
// Metrics displays:
|
||||
$("body").on('msg:metrics', '.receiver', function(e, update) {
|
||||
$(this).find(".metric").each(function() {
|
||||
var $el = $(this), metric = $el.data("metric"), prec = $el.data("prec"), scale = $el.data("scale");
|
||||
var $el = $(this), metric = $el.data("metric"), prec = $el.data("prec"), scale = $el.data("scale"), useUser = $el.data("user");
|
||||
if (!metric) return;
|
||||
// filter:
|
||||
var keys = metric.split(","), val;
|
||||
var metricName = "";
|
||||
for (var i=0; i<keys.length; i++) {
|
||||
if ((val = update[keys[i]]) != null) break;
|
||||
metricName = keys[i];
|
||||
if ((val = update[metricName]) != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (val == null) return;
|
||||
|
||||
// process:
|
||||
if ($el.hasClass("text")) {
|
||||
$el.children(".value").text(val);
|
||||
var elt = $el.children(".value");
|
||||
if (elt) elt.text(val);
|
||||
elt = $el.children(".unit");
|
||||
if (elt) elt.text(val);
|
||||
|
||||
} else if ($el.hasClass("number")) {
|
||||
var vf = val;
|
||||
if (scale != null) vf = Number(vf) * scale;
|
||||
if (scale != null)
|
||||
vf = Number(vf) * scale;
|
||||
else {
|
||||
var mun = units.userUnitLabelFromMetric(metricName);
|
||||
if (mun != "") {
|
||||
// If there's a .unit.. then convert it.
|
||||
item = $el.children(".unit");
|
||||
if (item) {
|
||||
item.text(mun);
|
||||
useUser = true;
|
||||
}
|
||||
}
|
||||
if (useUser)
|
||||
vf = units.convertMetricToUserUnits(vf, metricName);
|
||||
}
|
||||
if (prec != null) vf = Number(vf).toFixed(prec);
|
||||
$el.children(".value").text(vf);
|
||||
} else if ($el.hasClass("progress")) {
|
||||
|
|
BIN
OVMS.V3/components/ovms_webserver/docs/bms-cell-info.odg
Normal file
BIN
OVMS.V3/components/ovms_webserver/docs/bms-cell-info.odg
Normal file
Binary file not shown.
BIN
OVMS.V3/components/ovms_webserver/docs/bms-cell-info.png
Normal file
BIN
OVMS.V3/components/ovms_webserver/docs/bms-cell-info.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
BIN
OVMS.V3/components/ovms_webserver/docs/bms-cell-monitor.png
Normal file
BIN
OVMS.V3/components/ovms_webserver/docs/bms-cell-monitor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 81 KiB |
161
OVMS.V3/components/ovms_webserver/docs/bms-cell-monitor.rst
Normal file
161
OVMS.V3/components/ovms_webserver/docs/bms-cell-monitor.rst
Normal file
|
@ -0,0 +1,161 @@
|
|||
===============
|
||||
Battery Monitor
|
||||
===============
|
||||
|
||||
.. image:: bms-cell-monitor.png
|
||||
:width: 90%
|
||||
:align: center
|
||||
|
||||
The BMS cell monitor is a **live view** of the battery pack and cell status.
|
||||
It shows all individual cell voltages and module temperatures recorded
|
||||
by the BMS, their average values and standard deviations.
|
||||
|
||||
The battery monitoring availability and detail depends on the vehicle
|
||||
adaptor to provide cell voltage and temperature measurements. The BMS
|
||||
framework takes care of doing the statistics.
|
||||
|
||||
The OVMS BMS normally records over a typical usage period, i.e. a full
|
||||
driving or charging period. You can also issue a reset manually any time
|
||||
using the button (or command ``bms reset``).
|
||||
|
||||
All statistics (min/max values and deviations) relate to the recording
|
||||
period, so a reset clears these, as well as the warning and alert status
|
||||
of all cells.
|
||||
|
||||
Of course all data shown is also available as metrics, namely the
|
||||
``v.b.p.`` (vehicle battery pack) and ``v.b.c.`` (vehicle battery cell)
|
||||
range of metrics.
|
||||
|
||||
|
||||
-----------
|
||||
Chart Usage
|
||||
-----------
|
||||
|
||||
Voltage and temperature sensors normally differ in number, as voltages
|
||||
are measured for each cell bundle (cells connected in parallel), while
|
||||
temperatures only are measured for a cell module (multiple cell bundles
|
||||
connected in series). Accordingly the monitor is divided into a voltage
|
||||
and a temperature chart.
|
||||
|
||||
Click on the chart series names below the charts to show/hide the
|
||||
respective series or group of metrics in that chart.
|
||||
|
||||
The charts can be zoomed and pinched using the mouse or dual touch finger
|
||||
gestures as usual. When zoomed, a zoom reset button is shown in the upper
|
||||
right corner. To move the zoom window, hold the ``Ctrl`` key while clicking,
|
||||
or tap and move two fingers. Note: horizontal zoom needs an up to date
|
||||
firmware.
|
||||
|
||||
Hovering or clicking on a cell/module chart column will show the actual
|
||||
values (numbers) in a small overlay window.
|
||||
|
||||
Values may change while viewing the chart, that's normal: the chart is
|
||||
a live view of the actual current measurements. That allows to see how
|
||||
the cells respond to sudden high loads.
|
||||
|
||||
|
||||
-----------------------
|
||||
Cell/Module Info Detail
|
||||
-----------------------
|
||||
|
||||
.. image:: bms-cell-info.png
|
||||
:width: 90%
|
||||
:align: center
|
||||
|
||||
|
||||
-----------------
|
||||
Overall Pack Info
|
||||
-----------------
|
||||
|
||||
The table at the bottom shows the overall pack statistics in numbers.
|
||||
|
||||
This includes the overall cell/module averages, the maximum and minimum
|
||||
voltage/temperature readings recorded, and the current and recorded maximum
|
||||
standard deviation.
|
||||
|
||||
**On the cell gradient & max stddev deviation**: voltages are very volatile,
|
||||
as current battery cells immediately react to load changes. A high discharge
|
||||
pulse will lead to an instantaneous substantial drop of the cell voltages.
|
||||
|
||||
So, depending on how the vehicle's BMS does the measurements, a full series of
|
||||
voltages may include such a change in between some cells. That would lead to
|
||||
wrong standard deviations and possibly false alerts, so the BMS framework
|
||||
analyses the full voltage series for a gradient, and ignores the series
|
||||
if the configured threshold is exceeded.
|
||||
|
||||
The series is also ignored if the standard deviation exceeds the configured
|
||||
"max stddev deviation" value. Combine both thresholds to filter unusable
|
||||
series. The vehicle adaptor provides sensible default thresholds, but you
|
||||
may need to adjust them depending on the age and health of your battery.
|
||||
|
||||
|
||||
------------------------
|
||||
Cell Alert Configuration
|
||||
------------------------
|
||||
|
||||
Cell voltage and temperature warnings and alerts are triggered by cell
|
||||
deviation from the current average. Warnings and alerts are detected by
|
||||
the BMS framework in the background, so you don't need to keep the monitor
|
||||
open to get them.
|
||||
|
||||
Deviations exceeding configured threshold are shown color coded, yellow
|
||||
for warnings and red for alerts. Alerts will also trigger text notifications
|
||||
of type ``alert`` subtype ``batt.bms.alert`` unless disabled.
|
||||
|
||||
Click "Alert config" to change the thresholds or control text alert
|
||||
notifications. Adjust the warning & alert thresholds as needed.
|
||||
|
||||
The vehicle adaptor provides reasonable defaults for the warning and alert
|
||||
thresholds matching the specific type of battery normally built into the
|
||||
vehicle, but you may need to change the thresholds to adapt to the quality
|
||||
and age of your battery.
|
||||
|
||||
The BMS configuration can also be changed directly via the ``config``
|
||||
command. The parameters are located under ``vehicle``, issue
|
||||
``config list vehicle`` and look for parameter names including ``bms``.
|
||||
In case you don't see any, save some custom values in the UI to create
|
||||
them.
|
||||
|
||||
|
||||
---------------------
|
||||
Health Interpretation
|
||||
---------------------
|
||||
|
||||
You generally want your cells to be as close together as possible in terms
|
||||
of voltages and temperatures. When aging, deviations will rise, as internal
|
||||
resistances rise.
|
||||
|
||||
The weakest cell normally defines the overall discharge and charge limits
|
||||
of the pack, as the vehicle BMS normally cannot shift load around individual
|
||||
cells -- current flows through all cells equally (more or less). A weak cell
|
||||
will reach the safety cutoff limits first, causing the BMS to terminate
|
||||
discharging or charging or to limit the power levels available.
|
||||
|
||||
The higher the pack standard deviation the worse the overall battery
|
||||
performance. A high standard deviation is a sign for an old battery, or
|
||||
for a new battery with a very poor cell matching (read: poor build
|
||||
quality).
|
||||
|
||||
A high individual cell voltage deviation is a sign for a defective cell
|
||||
that should be checked and possibly replaced as soon as possible to avoid
|
||||
further damage.
|
||||
|
||||
A high voltage drop under load implies a high internal resistance and/or
|
||||
some chemical defect.
|
||||
|
||||
A high positive temperature deviation of a cell or module can be a sign for
|
||||
a chemical defect (e.g. dendrites causing short circuits) or for a bad
|
||||
connector (e.g. a lose screw). Both not only degrade the overall pack
|
||||
performance but can lead to battery fires in the worst case, so must be
|
||||
addressed as soon as possible.
|
||||
|
||||
Some temperature & voltage deviation may be normal, caused by the layout
|
||||
of the cells in your vehicle: cells placed closer to the outside will
|
||||
have a higher temperature variance than those deep within the pack, and
|
||||
a cell with higher temperature will have a higher voltage stability.
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -6,9 +6,28 @@ OVMS V3 is based on metrics. Metrics can be single numerical or textual values o
|
|||
like sets and arrays. The web framework keeps all metrics in a global object, which can be read
|
||||
simply by e.g. ``metrics["v.b.soc"]``.
|
||||
|
||||
In addition to the raw metric values, there are 2 main proxy arrays that give access to the
|
||||
user-configured versions of the raw metric values. The ``metrics_user`` array
|
||||
converts the 'metrics' value to user-configured value and the ``metrics_label`` array
|
||||
provides the corresponding label for that metric.
|
||||
So for example the user could configure distance values to be in miles, and in this case
|
||||
``metrics["v.p.odometer"]`` would still contain the value in km (the default) but
|
||||
``metrics_user["v.p.odometer"]`` would give the value converted to miles and
|
||||
``metrics_label["v.p.odometer"]`` would return "M".
|
||||
|
||||
The user conversion information is contained in another object ``units``. ``units.metrics``
|
||||
has the user configuration for each metric and ``units.prefs`` has the user configuration
|
||||
for each group of metrics (distance, temperature, consumption, pressure etc). There also some methods
|
||||
for general conversions allowing user preferences.
|
||||
- The method ``units.unitLabelToUser(unitType,name)`` will return the user
|
||||
defined label for that 'unitType', defaulting to ``name``.
|
||||
- The method ``units.unitValueToUser(unitType,value)`` will convert ``value``
|
||||
to the user defined unit (if set) for the group.
|
||||
|
||||
Metrics updates (as well as other updates) are sent to all DOM elements having the
|
||||
``receiver`` class. To hook into these updates, simply add an event listener for
|
||||
``msg:metrics``.
|
||||
``msg:metrics:``. The event ``msg:units:metrics`` is called when ``units.metrics`` is change
|
||||
and ``msg:units:prefs`` when ``units.prefs`` are changed.
|
||||
|
||||
Listening to the event is not necessary though if all you need is some metrics
|
||||
display. This is covered by the ``metric`` widget class family as shown here.
|
||||
|
@ -30,6 +49,11 @@ The following example covers…
|
|||
- Gauges
|
||||
- Charts
|
||||
|
||||
Where a number element of class 'metric' contains both elements of class
|
||||
'value' and 'unit', these will be automatically displayed in the units selected
|
||||
in the user preferences. Having a 'data-user' attribute will also cause the
|
||||
'value' element to be displayed in user units (unless 'data-scale' attribute is present).
|
||||
|
||||
Gauges & charts use the HighCharts library, which is included in the web server. The other widgets
|
||||
are simple standard Bootstrap widgets extended by an automatic metrics value update mechanism.
|
||||
|
||||
|
|
|
@ -1086,3 +1086,105 @@ void OvmsWebServer::HandleLogout(PageEntry_t& p, PageContext_t& c)
|
|||
"<script>loggedin = false; $(\"#menu\").load(\"/menu\"); loaduri(\"#main\", \"get\", \"/home\", {})</script>");
|
||||
c.done();
|
||||
}
|
||||
|
||||
// Dash Gauge implementations.
|
||||
//
|
||||
|
||||
dash_gauge_t::dash_gauge_t(const char *titlePrefix, metric_unit_t defUnit, metric_group_t group)
|
||||
{
|
||||
has_tick = false;
|
||||
title_prefix = titlePrefix ? titlePrefix : "";
|
||||
if (group == GrpNone)
|
||||
group = GetMetricGroup(defUnit);
|
||||
if (group == GrpOther)
|
||||
user_unit = defUnit;
|
||||
else
|
||||
user_unit = MyUnitConfig.GetUserUnit(group, defUnit);
|
||||
base_unit = defUnit;
|
||||
}
|
||||
float dash_gauge_t::UntConvert( float inValue ) const
|
||||
{
|
||||
return UnitConvert(base_unit, user_unit, inValue);
|
||||
}
|
||||
float dash_gauge_t::UntConvert( float inValue, float roundValue ) const
|
||||
{
|
||||
if (base_unit == user_unit)
|
||||
return inValue;
|
||||
return truncf(UnitConvert(base_unit, user_unit, inValue) / roundValue) * roundValue;
|
||||
}
|
||||
|
||||
void dash_gauge_t::SetMinMax( float minValue, float maxValue)
|
||||
{
|
||||
min_value = UntConvert(minValue);
|
||||
float temp_max = UntConvert(maxValue);
|
||||
if (min_value < temp_max)
|
||||
max_value = temp_max;
|
||||
else {
|
||||
max_value = min_value;
|
||||
min_value = temp_max;
|
||||
}
|
||||
}
|
||||
|
||||
void dash_gauge_t::SetMinMax( float minValue, float maxValue, float roundValue)
|
||||
{
|
||||
min_value = UntConvert(minValue, roundValue);
|
||||
float temp_max = UntConvert(maxValue, roundValue);
|
||||
if (min_value < temp_max)
|
||||
max_value = temp_max;
|
||||
else {
|
||||
max_value = min_value;
|
||||
min_value = temp_max;
|
||||
}
|
||||
}
|
||||
void dash_gauge_t::SetTick( float tickValue)
|
||||
{
|
||||
tick_value = UntConvert(tickValue);
|
||||
has_tick =true;
|
||||
}
|
||||
void dash_gauge_t::SetTick( float tickValue, float roundValue)
|
||||
{
|
||||
tick_value = UntConvert(tickValue);
|
||||
has_tick = true;
|
||||
}
|
||||
void dash_gauge_t::DoAddBand( const std::string &colour, float minValue, float maxValue, bool round, float roundValue)
|
||||
{
|
||||
dash_plot_band_t new_band;
|
||||
new_band.colour = colour;
|
||||
new_band.min_value = round ? UntConvert(minValue,roundValue) : UntConvert(minValue);
|
||||
float temp_max = round ? UntConvert(maxValue, roundValue) : UntConvert(maxValue);
|
||||
if (new_band.min_value <= temp_max) {
|
||||
new_band.max_value = temp_max;
|
||||
bands.insert(bands.end(), new_band);
|
||||
} else
|
||||
{
|
||||
new_band.max_value = new_band.min_value;
|
||||
new_band.min_value = temp_max;
|
||||
bands.insert(bands.begin(), new_band);
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream &dash_gauge_t::Output(std::ostream &ostream) const
|
||||
{
|
||||
ostream <<
|
||||
"{"
|
||||
"title: { text: '"<< title_prefix << PageContext::encode_html(OvmsMetricUnitLabel(user_unit)) << "' },";
|
||||
if (min_value < max_value) {
|
||||
ostream <<
|
||||
"min: " << min_value << ", max: " << max_value << ",";
|
||||
}
|
||||
if (has_tick)
|
||||
ostream << "tickInterval: " << tick_value << ",";
|
||||
|
||||
ostream << "plotBands: [";
|
||||
bool first = true;
|
||||
for (auto iter = bands.begin() ; iter != bands.end(); ++iter) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
ostream << ",";
|
||||
ostream <<
|
||||
"{ from: " << iter->min_value << ", to: " << iter->max_value << ", className: '" << iter->colour <<"-band' }";
|
||||
}
|
||||
ostream << "]}";
|
||||
return ostream;
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ struct PageContext : public ExternalRamAllocated
|
|||
void print(const std::string text);
|
||||
void print(const extram::string text);
|
||||
void print(const char* text);
|
||||
void printf(const char *fmt, ...);
|
||||
void printf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
void done();
|
||||
void panel_start(const char* type, const char* title);
|
||||
void panel_end(const char* footer="");
|
||||
|
@ -367,6 +367,8 @@ enum WebSocketTxJobType
|
|||
WSTX_Config, // payload: config (todo)
|
||||
WSTX_Notify, // payload: notification
|
||||
WSTX_LogBuffers, // payload: logbuffers
|
||||
WSTX_UnitMetricUpdate, // payload: -
|
||||
WSTX_UnitPrefsUpdate, // payload: -
|
||||
};
|
||||
|
||||
struct WebSocketTxJob
|
||||
|
@ -412,6 +414,10 @@ class WebSocketHandler : public MgHandler, public OvmsWriter
|
|||
void Unsubscribe(std::string topic);
|
||||
bool IsSubscribedTo(std::string topic);
|
||||
|
||||
void SubscriptionChanged();
|
||||
void UnitsCheckSubscribe();
|
||||
void UnitsCheckVehicleSubscribe();
|
||||
|
||||
// OvmsWriter:
|
||||
public:
|
||||
void Log(LogBuffers* message);
|
||||
|
@ -428,7 +434,10 @@ class WebSocketHandler : public MgHandler, public OvmsWriter
|
|||
WebSocketTxJob m_job = {};
|
||||
int m_sent = 0;
|
||||
int m_ack = 0;
|
||||
int m_last = 0; // last entry sent up
|
||||
std::set<std::string> m_subscriptions;
|
||||
bool m_units_subscribed;
|
||||
bool m_units_prefs_subscribed;
|
||||
};
|
||||
|
||||
struct WebSocketSlot
|
||||
|
@ -469,7 +478,7 @@ class HttpCommandStream : public OvmsShell, public MgHandler
|
|||
void Initialize(bool print);
|
||||
virtual bool IsInteractive() { return false; }
|
||||
int puts(const char* s);
|
||||
int printf(const char* fmt, ...);
|
||||
int printf(const char* fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
ssize_t write(const void *buf, size_t nbyte);
|
||||
void Log(LogBuffers* message);
|
||||
};
|
||||
|
@ -536,7 +545,7 @@ class OvmsWebServer : public ExternalRamAllocated
|
|||
static void HandleLogin(PageEntry_t& p, PageContext_t& c);
|
||||
static void HandleLogout(PageEntry_t& p, PageContext_t& c);
|
||||
static void OutputReboot(PageEntry_t& p, PageContext_t& c);
|
||||
static void OutputReconnect(PageEntry_t& p, PageContext_t& c, const char* info=NULL);
|
||||
static void OutputReconnect(PageEntry_t& p, PageContext_t& c, const char* info=NULL, const char* cmd=NULL);
|
||||
|
||||
public:
|
||||
static void HandleStatus(PageEntry_t& p, PageContext_t& c);
|
||||
|
@ -610,6 +619,80 @@ class OvmsWebServer : public ExternalRamAllocated
|
|||
|
||||
extern OvmsWebServer MyWebServer;
|
||||
|
||||
/** Dashboard Gauge generator.
|
||||
* Handles unit conversions.
|
||||
*/
|
||||
struct dash_gauge_t {
|
||||
protected:
|
||||
struct dash_plot_band_t {
|
||||
std::string colour;
|
||||
float min_value, max_value;
|
||||
};
|
||||
std::string title_prefix;
|
||||
metric_unit_t user_unit, base_unit;
|
||||
float min_value, max_value, tick_value;
|
||||
bool has_tick;
|
||||
std::vector<dash_plot_band_t> bands;
|
||||
void DoAddBand( const std::string &colour, float minValue, float maxValue, bool round, float roundValue);
|
||||
public:
|
||||
|
||||
/**
|
||||
* @param titlePrefix The title/caption prefix (to the unit)
|
||||
* @param defUnit The unit used as a default for these metrics.
|
||||
* @param group (Optional) The group of units it belong to.
|
||||
*/
|
||||
dash_gauge_t(const char *titlePrefix, metric_unit_t defUnit, metric_group_t group = GrpNone);
|
||||
/**
|
||||
* Convert a unit to the user unit.
|
||||
*/
|
||||
float UntConvert( float inValue ) const;
|
||||
/**
|
||||
* Convert a unit to the user unit with rounding to the nearest value.
|
||||
*/
|
||||
float UntConvert( float inValue, float roundValue ) const;
|
||||
/**
|
||||
* Set the minimum and maximum values for the gauge (in original units).
|
||||
*/
|
||||
void SetMinMax( float minValue, float maxValue);
|
||||
/**
|
||||
* Set the minimum and maximum values for the gauge (in original units) including
|
||||
* rounding to the nearest value.
|
||||
*/
|
||||
void SetMinMax( float minValue, float maxValue, float roundValue);
|
||||
/**
|
||||
* Set the tickmark intervals (in original units).
|
||||
*/
|
||||
void SetTick( float tickValue);
|
||||
/**
|
||||
* Set the tickmark intervals (in original units) with rounding to nearest.
|
||||
*/
|
||||
void SetTick( float tickValue, float roundValue);
|
||||
/** Zero the minimum. Used when 0 cannot be originally used as a minimum.
|
||||
*/
|
||||
inline void ZeroMin() { if (max_value > 0) min_value = 0; }
|
||||
|
||||
/** Add a colour band to the gauge.
|
||||
*/
|
||||
inline void AddBand( const std::string &colour, float minValue, float maxValue)
|
||||
{
|
||||
DoAddBand(colour, minValue, maxValue, false, 0);
|
||||
}
|
||||
/** Add a colour band to the gauge with rounding to the nearest value.
|
||||
*/
|
||||
inline void AddBand( const std::string &colour, float minValue, float maxValue, float roundValue)
|
||||
{
|
||||
DoAddBand(colour, minValue, maxValue, true, roundValue);
|
||||
}
|
||||
|
||||
/** Output this element to a stream.
|
||||
*/
|
||||
std::ostream &Output(std::ostream &ostream) const;
|
||||
};
|
||||
inline std::ostream &operator<<(std::ostream &out, const dash_gauge_t& gauge)
|
||||
{
|
||||
return gauge.Output(out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* DashboardConfig:
|
||||
|
|
|
@ -71,7 +71,12 @@ WebSocketHandler::WebSocketHandler(mg_connection* nc, size_t slot, size_t modifi
|
|||
m_jobqueue_overflow_dropcnt = 0;
|
||||
m_jobqueue_overflow_dropcntref = 0;
|
||||
m_job.type = WSTX_None;
|
||||
m_sent = m_ack = 0;
|
||||
m_sent = m_ack = m_last = 0;
|
||||
m_units_subscribed = false;
|
||||
m_units_prefs_subscribed = false;
|
||||
|
||||
MyMetrics.InitialiseSlot(m_slot);
|
||||
MyUnitConfig.InitialiseSlot(m_slot);
|
||||
|
||||
// Register as logging console:
|
||||
SetMonitoring(true);
|
||||
|
@ -116,39 +121,42 @@ void WebSocketHandler::ProcessTxJob()
|
|||
case WSTX_MetricsAll:
|
||||
case WSTX_MetricsUpdate:
|
||||
{
|
||||
// Note: this loops over the metrics by index, keeping the checked count
|
||||
// in m_sent. It will not detect new metrics added between polls if they are
|
||||
// inserted before m_sent, so new metrics may not be sent until first changed.
|
||||
// Note: this loops over the metrics by index, keeping the last checked position
|
||||
// in m_last. It will not detect new metrics added between polls if they are
|
||||
// inserted before m_last, so new metrics may not be sent until first changed.
|
||||
// The Metrics set normally is static, so this should be no problem.
|
||||
|
||||
// find start:
|
||||
int i;
|
||||
OvmsMetric* m;
|
||||
for (i=0, m=MyMetrics.m_first; i < m_sent && m != NULL; m=m->m_next, i++);
|
||||
for (i=0, m=MyMetrics.m_first; i < m_last && m != NULL; m=m->m_next, i++);
|
||||
|
||||
// build msg:
|
||||
std::string msg;
|
||||
msg.reserve(2*XFER_CHUNK_SIZE+128);
|
||||
msg = "{\"metrics\":{";
|
||||
for (i=0; m && msg.size() < XFER_CHUNK_SIZE; m=m->m_next) {
|
||||
if (m->IsModifiedAndClear(m_modifier) || m_job.type == WSTX_MetricsAll) {
|
||||
if (i) msg += ',';
|
||||
msg += '\"';
|
||||
msg += m->m_name;
|
||||
msg += "\":";
|
||||
msg += m->AsJSON();
|
||||
i++;
|
||||
if (m) {
|
||||
std::string msg;
|
||||
msg.reserve(2*XFER_CHUNK_SIZE+128);
|
||||
msg = "{\"metrics\":{";
|
||||
for (i=0; m && msg.size() < XFER_CHUNK_SIZE; m=m->m_next) {
|
||||
++m_last;
|
||||
if (m->IsModifiedAndClear(m_modifier) || m_job.type == WSTX_MetricsAll) {
|
||||
if (i) msg += ',';
|
||||
msg += '\"';
|
||||
msg += m->m_name;
|
||||
msg += "\":";
|
||||
msg += m->AsJSON();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// send msg:
|
||||
if (i) {
|
||||
msg += "}}";
|
||||
ESP_EARLY_LOGV(TAG, "WebSocket msg: %s", msg.c_str());
|
||||
mg_send_websocket_frame(m_nc, WEBSOCKET_OP_TEXT, msg.data(), msg.size());
|
||||
m_sent += i;
|
||||
}
|
||||
}
|
||||
|
||||
// send msg:
|
||||
if (i) {
|
||||
msg += "}}";
|
||||
ESP_EARLY_LOGV(TAG, "WebSocket msg: %s", msg.c_str());
|
||||
mg_send_websocket_frame(m_nc, WEBSOCKET_OP_TEXT, msg.data(), msg.size());
|
||||
m_sent += i;
|
||||
}
|
||||
|
||||
|
||||
// done?
|
||||
if (!m && m_ack == m_sent) {
|
||||
if (m_sent)
|
||||
|
@ -158,7 +166,135 @@ void WebSocketHandler::ProcessTxJob()
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case WSTX_UnitMetricUpdate:
|
||||
{
|
||||
// Note: this loops over the metrics by index, keeping the last checked position
|
||||
// in m_last. It will not detect new metrics added between polls if they are
|
||||
// inserted before m_last, so new metrics may not be sent until first changed.
|
||||
// The Metrics set normally is static, so this should be no problem.
|
||||
|
||||
ESP_EARLY_LOGD(TAG, "WebSocketHandler[%p/%d]: ProcessTxJob MetricsUnitUpdate, last=%d sent=%d ack=%d", m_nc, m_modifier, m_last, m_sent, m_ack);
|
||||
// find start:
|
||||
int i;
|
||||
OvmsMetric* m;
|
||||
for (i=0, m=MyMetrics.m_first; i < m_last && m != NULL; m=m->m_next, i++);
|
||||
ESP_EARLY_LOGD(TAG, "WebSocketHandler[%p/%d]: ProcessTxJob MetricsUnitUpdate, i=%d", m_nc, m_modifier, i);
|
||||
if (m) { // Bypass this if we are on the 'just sent' leg.
|
||||
// build msg:
|
||||
std::string msg;
|
||||
msg.reserve(2*XFER_CHUNK_SIZE+128);
|
||||
msg = "{\"units\":{\"metrics\":{";
|
||||
|
||||
// Cache the user mappings for each group.
|
||||
for (i=0; m && msg.size() < XFER_CHUNK_SIZE; m=m->m_next) {
|
||||
++m_last;
|
||||
bool send = m->IsUnitSendAndClear(m_modifier);
|
||||
if (send) {
|
||||
if (i)
|
||||
msg += ',';
|
||||
metric_unit_t units = m->m_units;
|
||||
metric_unit_t user_units = MyUnitConfig.GetUserUnit(units);
|
||||
if (user_units == UnitNotFound)
|
||||
user_units = Native;
|
||||
std::string unitlabel = OvmsMetricUnitLabel((user_units == Native) ? units : user_units);
|
||||
|
||||
const char *metricname = (units == Native) ? "Other" : OvmsMetricUnitName(units);
|
||||
if (metricname == NULL)
|
||||
metricname = "";
|
||||
const char *user_metricname = (user_units == Native) ? metricname : OvmsMetricUnitName(user_units);
|
||||
if (user_metricname == NULL)
|
||||
user_metricname = metricname;
|
||||
|
||||
std::string entry = string_format("\"%s\":{\"native\":\"%s\",\"code\":\"%s\",\"label\":\"%s\"}",
|
||||
m->m_name, metricname, user_metricname, json_encode(unitlabel).c_str()
|
||||
);
|
||||
msg += entry;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// send msg:
|
||||
if (i) {
|
||||
msg += "}}}";
|
||||
ESP_EARLY_LOGD(TAG, "WebSocket msg: %s", msg.c_str());
|
||||
mg_send_websocket_frame(m_nc, WEBSOCKET_OP_TEXT, msg.data(), msg.size());
|
||||
m_sent += i;
|
||||
}
|
||||
}
|
||||
|
||||
// done?
|
||||
if (!m && m_ack == m_sent) {
|
||||
if (m_sent)
|
||||
ESP_EARLY_LOGD(TAG, "WebSocketHandler[%p/%d]: ProcessTxJob MetricsUnitsUpdate done, sent=%d metrics", m_nc, m_modifier, m_sent);
|
||||
ClearTxJob(m_job);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WSTX_UnitPrefsUpdate:
|
||||
{
|
||||
// Note: this loops over the metrics by index, keeping the last checked position
|
||||
// in m_last. It will not detect new metrics added between polls if they are
|
||||
// inserted before m_last, so new metrics may not be sent until first changed.
|
||||
// The Metrics set normally is static, so this should be no problem.
|
||||
|
||||
ESP_EARLY_LOGD(TAG, "WebSocketHandler[%p/%d]: ProcessTxJob MetricsVehicleUpdate, last=%d sent=%d ack=%d", m_nc, m_modifier, m_last, m_sent, m_ack);
|
||||
if (m_last < MyUnitConfig.config_groups.size()) {
|
||||
// Bypass this if we are on the 'just sent' leg.
|
||||
// build msg:
|
||||
std::string msg;
|
||||
msg.reserve(2*XFER_CHUNK_SIZE+128);
|
||||
msg = "{\"units\":{\"prefs\":{";
|
||||
|
||||
// Cache the user mappings for each group.
|
||||
int i = 0;
|
||||
for (int groupindex = m_last;
|
||||
groupindex < MyUnitConfig.config_groups.size() && msg.size() < XFER_CHUNK_SIZE;
|
||||
++groupindex) {
|
||||
++m_last;
|
||||
metric_group_t group = MyUnitConfig.config_groups[groupindex];
|
||||
|
||||
bool send = MyUnitConfig.IsModifiedAndClear(group, m_modifier);
|
||||
if (send) {
|
||||
metric_unit_t user_units = MyUnitConfig.GetUserUnit(group);
|
||||
std::string unitLabel;
|
||||
if (user_units == UnitNotFound)
|
||||
unitLabel = "null";
|
||||
else {
|
||||
|
||||
unitLabel = '"';
|
||||
unitLabel += json_encode(std::string(OvmsMetricUnitLabel(user_units)));
|
||||
unitLabel += '"';
|
||||
}
|
||||
const char *groupName = OvmsMetricGroupName(group);
|
||||
const char *unitName = (user_units == Native) ? "Native" : OvmsMetricUnitName(user_units);
|
||||
std::string entry = string_format("%s\"%s\":{\"unit\":\"%s\",\"label\":%s}",
|
||||
i ? "," : "",
|
||||
groupName, unitName, unitLabel.c_str()
|
||||
);
|
||||
msg += entry;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// send msg:
|
||||
if (i) {
|
||||
msg += "}}}";
|
||||
ESP_EARLY_LOGD(TAG, "WebSocket msg: %s", msg.c_str());
|
||||
mg_send_websocket_frame(m_nc, WEBSOCKET_OP_TEXT, msg.data(), msg.size());
|
||||
m_sent += i;
|
||||
}
|
||||
}
|
||||
|
||||
// done?
|
||||
if (m_last >= MyUnitConfig.config_groups.size() && m_ack == m_sent) {
|
||||
if (m_sent)
|
||||
ESP_EARLY_LOGD(TAG, "WebSocketHandler[%p/%d]: ProcessTxJob MetricsUnitsUpdate done, sent=%d metrics", m_nc, m_modifier, m_sent);
|
||||
ClearTxJob(m_job);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case WSTX_Notify:
|
||||
{
|
||||
if (m_sent && m_ack == m_job.notification->GetValueSize()+1) {
|
||||
|
@ -300,7 +436,7 @@ bool WebSocketHandler::GetNextTxJob()
|
|||
if (!m_jobqueue) return false;
|
||||
if (xQueueReceive(m_jobqueue, &m_job, 0) == pdTRUE) {
|
||||
// init new job state:
|
||||
m_sent = m_ack = 0;
|
||||
m_sent = m_ack = m_last = 0;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -610,17 +746,31 @@ void OvmsWebServer::UpdateTicker(TimerHandle_t timer)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// trigger metrics update:
|
||||
|
||||
// trigger metrics update if required.
|
||||
unsigned long mask_all = MyMetrics.GetUnitSendAll();
|
||||
for (auto slot: MyWebServer.m_client_slots) {
|
||||
if (slot.handler)
|
||||
if (slot.handler) {
|
||||
slot.handler->AddTxJob({ WSTX_MetricsUpdate, NULL });
|
||||
if (slot.handler->m_units_subscribed) {
|
||||
unsigned long bit = 1ul << slot.handler->m_modifier;
|
||||
bool addJob = (bit & mask_all) != 0;
|
||||
if (addJob) {
|
||||
// Trigger Units update:
|
||||
slot.handler->AddTxJob({ WSTX_UnitMetricUpdate, NULL });
|
||||
}
|
||||
}
|
||||
if (slot.handler->m_units_prefs_subscribed) {
|
||||
// Triger unit group config update.
|
||||
if (MyUnitConfig.HasModified(slot.handler->m_modifier))
|
||||
slot.handler->AddTxJob({ WSTX_UnitPrefsUpdate, NULL });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
xSemaphoreGive(MyWebServer.m_client_mutex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notifications:
|
||||
*/
|
||||
|
@ -642,18 +792,57 @@ void WebSocketHandler::Subscribe(std::string topic)
|
|||
}
|
||||
m_subscriptions.insert(topic);
|
||||
ESP_LOGD(TAG, "WebSocketHandler[%p]: subscription '%s' added", m_nc, topic.c_str());
|
||||
SubscriptionChanged();
|
||||
}
|
||||
|
||||
void WebSocketHandler::Unsubscribe(std::string topic)
|
||||
{
|
||||
bool changed = false;
|
||||
for (auto it = m_subscriptions.begin(); it != m_subscriptions.end();) {
|
||||
if (mg_mqtt_match_topic_expression(mg_mk_str(topic.c_str()), mg_mk_str((*it).c_str()))) {
|
||||
ESP_LOGD(TAG, "WebSocketHandler[%p]: subscription '%s' removed", m_nc, (*it).c_str());
|
||||
it = m_subscriptions.erase(it);
|
||||
changed = true;
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
if (changed)
|
||||
SubscriptionChanged();
|
||||
}
|
||||
|
||||
void WebSocketHandler::SubscriptionChanged()
|
||||
{
|
||||
UnitsCheckSubscribe();
|
||||
UnitsCheckVehicleSubscribe();
|
||||
}
|
||||
|
||||
void WebSocketHandler::UnitsCheckSubscribe()
|
||||
{
|
||||
bool newSubscribe = IsSubscribedTo("units/metrics");
|
||||
if (newSubscribe != m_units_subscribed) {
|
||||
m_units_subscribed = newSubscribe;
|
||||
if (newSubscribe) {
|
||||
ESP_LOGD(TAG, "WebSocketHandler[%p/%d]: Subscribed to units/metrics", m_nc, m_modifier);
|
||||
MyMetrics.SetAllUnitSend(m_modifier);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "WebSocketHandler[%p/%d]: Unsubscribed from units/metrics", m_nc, m_modifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebSocketHandler::UnitsCheckVehicleSubscribe()
|
||||
{
|
||||
bool newSubscribe = IsSubscribedTo("units/prefs");
|
||||
if (newSubscribe != m_units_prefs_subscribed) {
|
||||
m_units_prefs_subscribed = newSubscribe;
|
||||
if (newSubscribe) {
|
||||
ESP_LOGD(TAG, "WebSocketHandler[%p/%d]: Subscribed to units/prefs", m_nc, m_modifier);
|
||||
MyUnitConfig.InitialiseSlot(m_modifier);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "WebSocketHandler[%p/%d]: Unsubscribed from units/prefs", m_nc, m_modifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WebSocketHandler::IsSubscribedTo(std::string topic)
|
||||
|
|
|
@ -74,6 +74,12 @@ void OvmsWebServer::HandleStatus(PageEntry_t& p, PageContext_t& c)
|
|||
c.done();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// "network restart", "wifi reconnect"
|
||||
OutputReconnect(p, c, NULL, cmd.c_str());
|
||||
c.done();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PAGE_HOOK("body.pre");
|
||||
|
@ -101,6 +107,13 @@ void OvmsWebServer::HandleStatus(PageEntry_t& p, PageContext_t& c)
|
|||
"<div class=\"metric number\" data-metric=\"m.net.sq\"><span class=\"value\">?</span><span class=\"unit\">dBm</span></div>"
|
||||
"</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<th>GPS</th>"
|
||||
"<td>"
|
||||
"<div class=\"metric number\" data-metric=\"v.p.satcount\"><span class=\"value\">?</span><span class=\"unit\">Satellites</span></div>"
|
||||
"<div class=\"metric number\" data-metric=\"v.p.gpssq\"><span class=\"value\">?</span><span class=\"unit\">%</span></div>"
|
||||
"</td>"
|
||||
"</tr>"
|
||||
"<tr>"
|
||||
"<th>Main battery</th>"
|
||||
"<td>"
|
||||
|
@ -137,7 +150,7 @@ void OvmsWebServer::HandleStatus(PageEntry_t& p, PageContext_t& c)
|
|||
output = ExecuteCommand("stat");
|
||||
c.printf("<samp class=\"monitor\" id=\"vehicle-status\" data-updcmd=\"stat\" data-events=\"vehicle.charge\">%s</samp>", _html(output));
|
||||
output = ExecuteCommand("location status");
|
||||
c.printf("<samp class=\"monitor\" data-updcmd=\"location status\" data-events=\"gps.lock|location\">%s</samp>", _html(output));
|
||||
c.printf("<samp class=\"monitor\" data-updcmd=\"location status\" data-events=\"gps.lock|gps.sq|location\">%s</samp>", _html(output));
|
||||
c.panel_end(
|
||||
"<ul class=\"list-inline\">"
|
||||
"<li><button type=\"button\" class=\"btn btn-default btn-sm\" data-target=\"#vehicle-cmdres\" data-cmd=\"charge start\">Start charge</button></li>"
|
||||
|
@ -202,7 +215,10 @@ void OvmsWebServer::HandleStatus(PageEntry_t& p, PageContext_t& c)
|
|||
c.panel_start("primary", "Network");
|
||||
output = ExecuteCommand("network status");
|
||||
c.printf("<samp class=\"monitor\" data-updcmd=\"network status\" data-events=\"^network\">%s</samp>", _html(output));
|
||||
c.panel_end();
|
||||
c.panel_end(
|
||||
"<ul class=\"list-inline\">"
|
||||
"<li><button type=\"button\" class=\"btn btn-default btn-sm\" name=\"action\" value=\"network restart\">Restart network</button></li>"
|
||||
"</ul>");
|
||||
|
||||
c.print(
|
||||
"</div>"
|
||||
|
@ -211,7 +227,10 @@ void OvmsWebServer::HandleStatus(PageEntry_t& p, PageContext_t& c)
|
|||
c.panel_start("primary", "Wifi");
|
||||
output = ExecuteCommand("wifi status");
|
||||
c.printf("<samp class=\"monitor\" data-updcmd=\"wifi status\" data-events=\"\\.wifi\\.\">%s</samp>", _html(output));
|
||||
c.panel_end();
|
||||
c.panel_end(
|
||||
"<ul class=\"list-inline\">"
|
||||
"<li><button type=\"button\" class=\"btn btn-default btn-sm\" name=\"action\" value=\"wifi reconnect\">Reconnect Wifi</button></li>"
|
||||
"</ul>");
|
||||
|
||||
c.print(
|
||||
"</div>"
|
||||
|
@ -222,8 +241,10 @@ void OvmsWebServer::HandleStatus(PageEntry_t& p, PageContext_t& c)
|
|||
c.printf("<samp class=\"monitor\" data-updcmd=\"cellular status\" data-events=\"\\.modem\\.\">%s</samp>", _html(output));
|
||||
c.panel_end(
|
||||
"<ul class=\"list-inline\">"
|
||||
"<li><button type=\"button\" class=\"btn btn-default btn-sm\" data-target=\"#modem-cmdres\" data-cmd=\"power cellular on\">Start cellular modem</button></li>"
|
||||
"<li><button type=\"button\" class=\"btn btn-default btn-sm\" data-target=\"#modem-cmdres\" data-cmd=\"power cellular off\">Stop cellular modem</button></li>"
|
||||
"<li><button type=\"button\" class=\"btn btn-default btn-sm\" data-target=\"#modem-cmdres\" data-cmd=\"power cellular on\">Start modem</button></li>"
|
||||
"<li><button type=\"button\" class=\"btn btn-default btn-sm\" data-target=\"#modem-cmdres\" data-cmd=\"power cellular off\">Stop modem</button></li>"
|
||||
"<li><button type=\"button\" class=\"btn btn-default btn-sm\" data-target=\"#modem-cmdres\" data-cmd=\"cellular gps start\">Start GPS</button></li>"
|
||||
"<li><button type=\"button\" class=\"btn btn-default btn-sm\" data-target=\"#modem-cmdres\" data-cmd=\"cellular gps stop\">Stop GPS</button></li>"
|
||||
"<li><samp id=\"modem-cmdres\" class=\"samp-inline\"></samp></li>"
|
||||
"</ul>");
|
||||
|
||||
|
@ -584,9 +605,13 @@ void OvmsWebServer::HandleCfgPassword(PageEntry_t& p, PageContext_t& c)
|
|||
void OvmsWebServer::HandleCfgVehicle(PageEntry_t& p, PageContext_t& c)
|
||||
{
|
||||
std::string error, info;
|
||||
std::string vehicleid, vehicletype, vehiclename, timezone, timezone_region, units_distance, pin;
|
||||
std::string vehicleid, vehicletype, vehiclename, timezone, timezone_region, pin;
|
||||
std::string bat12v_factor, bat12v_ref, bat12v_alert;
|
||||
|
||||
std::map<metric_group_t,std::string> units_values;
|
||||
metric_group_list_t unit_groups;
|
||||
OvmsMetricGroupConfigList(unit_groups);
|
||||
|
||||
if (c.method == "POST") {
|
||||
// process form submission:
|
||||
vehicleid = c.getvar("vehicleid");
|
||||
|
@ -594,7 +619,13 @@ void OvmsWebServer::HandleCfgVehicle(PageEntry_t& p, PageContext_t& c)
|
|||
vehiclename = c.getvar("vehiclename");
|
||||
timezone = c.getvar("timezone");
|
||||
timezone_region = c.getvar("timezone_region");
|
||||
units_distance = c.getvar("units_distance");
|
||||
for ( auto grpiter = unit_groups.begin(); grpiter != unit_groups.end(); ++grpiter) {
|
||||
std::string name = OvmsMetricGroupName(*grpiter);
|
||||
std::string cfg = "units_";
|
||||
cfg += name;
|
||||
units_values[*grpiter] = c.getvar(cfg);
|
||||
}
|
||||
|
||||
bat12v_factor = c.getvar("bat12v_factor");
|
||||
bat12v_ref = c.getvar("bat12v_ref");
|
||||
bat12v_alert = c.getvar("bat12v_alert");
|
||||
|
@ -620,7 +651,12 @@ void OvmsWebServer::HandleCfgVehicle(PageEntry_t& p, PageContext_t& c)
|
|||
MyConfig.SetParamValue("vehicle", "name", vehiclename);
|
||||
MyConfig.SetParamValue("vehicle", "timezone", timezone);
|
||||
MyConfig.SetParamValue("vehicle", "timezone_region", timezone_region);
|
||||
MyConfig.SetParamValue("vehicle", "units.distance", units_distance);
|
||||
for ( auto grpiter = unit_groups.begin(); grpiter != unit_groups.end(); ++grpiter) {
|
||||
std::string name = OvmsMetricGroupName(*grpiter);
|
||||
std::string value = units_values[*grpiter];
|
||||
OvmsMetricSetUserConfig(*grpiter, value);
|
||||
}
|
||||
|
||||
MyConfig.SetParamValue("system.adc", "factor12v", bat12v_factor);
|
||||
MyConfig.SetParamValue("vehicle", "12v.ref", bat12v_ref);
|
||||
MyConfig.SetParamValue("vehicle", "12v.alert", bat12v_alert);
|
||||
|
@ -649,7 +685,8 @@ void OvmsWebServer::HandleCfgVehicle(PageEntry_t& p, PageContext_t& c)
|
|||
vehiclename = MyConfig.GetParamValue("vehicle", "name");
|
||||
timezone = MyConfig.GetParamValue("vehicle", "timezone");
|
||||
timezone_region = MyConfig.GetParamValue("vehicle", "timezone_region");
|
||||
units_distance = MyConfig.GetParamValue("vehicle", "units.distance");
|
||||
for ( auto grpiter = unit_groups.begin(); grpiter != unit_groups.end(); ++grpiter)
|
||||
units_values[*grpiter] = OvmsMetricGetUserConfig(*grpiter);
|
||||
bat12v_factor = MyConfig.GetParamValue("system.adc", "factor12v");
|
||||
bat12v_ref = MyConfig.GetParamValue("vehicle", "12v.ref");
|
||||
bat12v_alert = MyConfig.GetParamValue("vehicle", "12v.alert");
|
||||
|
@ -696,10 +733,40 @@ void OvmsWebServer::HandleCfgVehicle(PageEntry_t& p, PageContext_t& c)
|
|||
, _attr(timezone_region)
|
||||
, _attr(timezone));
|
||||
|
||||
c.input_radiobtn_start("Distance units", "units_distance");
|
||||
c.input_radiobtn_option("units_distance", "Kilometers", "K", units_distance == "K");
|
||||
c.input_radiobtn_option("units_distance", "Miles", "M", units_distance == "M");
|
||||
c.input_radiobtn_end();
|
||||
for ( auto grpiter = unit_groups.begin(); grpiter != unit_groups.end(); ++grpiter) {
|
||||
std::string name = OvmsMetricGroupName(*grpiter);
|
||||
metric_unit_set_t group_units;
|
||||
if (OvmsMetricGroupUnits(*grpiter,group_units)) {
|
||||
bool use_select = group_units.size() > 3;
|
||||
std::string cfg = "units_";
|
||||
cfg += name;
|
||||
std::string value = units_values[*grpiter];
|
||||
if (use_select)
|
||||
c.input_select_start(OvmsMetricGroupLabel(*grpiter), cfg.c_str() );
|
||||
else
|
||||
c.input_radiobtn_start(OvmsMetricGroupLabel(*grpiter), cfg.c_str() );
|
||||
|
||||
bool checked = value.empty();
|
||||
if (use_select)
|
||||
c.input_select_option( "Default", "", checked);
|
||||
else
|
||||
c.input_radiobtn_option(cfg.c_str(), "Default", "", checked);
|
||||
for (auto unititer = group_units.begin(); unititer != group_units.end(); ++unititer) {
|
||||
const char* unit_name = OvmsMetricUnitName(*unititer);
|
||||
const char* unit_label = OvmsMetricUnitLabel(*unititer);
|
||||
checked = value == unit_name;
|
||||
if (use_select)
|
||||
c.input_select_option( unit_label, unit_name, checked);
|
||||
else
|
||||
c.input_radiobtn_option(cfg.c_str(), unit_label, unit_name, checked);
|
||||
}
|
||||
if (use_select)
|
||||
c.input_select_end();
|
||||
else
|
||||
c.input_radiobtn_end();
|
||||
}
|
||||
}
|
||||
|
||||
c.input_password("PIN", "pin", "", "empty = no change",
|
||||
"<p>Vehicle PIN code used for unlocking etc.</p>", "autocomplete=\"section-vehiclepin new-password\"");
|
||||
|
||||
|
@ -956,8 +1023,7 @@ void OvmsWebServer::HandleCfgPushover(PageEntry_t& p, PageContext_t& c)
|
|||
}
|
||||
|
||||
if (error == "") {
|
||||
if (c.getvar("action") == "save")
|
||||
{
|
||||
if (c.getvar("action") == "save") {
|
||||
// save:
|
||||
param->m_map.clear();
|
||||
param->m_map = std::move(pmap);
|
||||
|
@ -968,9 +1034,8 @@ void OvmsWebServer::HandleCfgPushover(PageEntry_t& p, PageContext_t& c)
|
|||
OutputHome(p, c);
|
||||
c.done();
|
||||
return;
|
||||
}
|
||||
else if (c.getvar("action") == "test")
|
||||
{
|
||||
} else if (c.getvar("action") == "test")
|
||||
{
|
||||
std::string reply;
|
||||
std::string popup;
|
||||
c.head(200);
|
||||
|
@ -984,10 +1049,10 @@ void OvmsWebServer::HandleCfgPushover(PageEntry_t& p, PageContext_t& c)
|
|||
atoi(c.getvar("retry").c_str()),
|
||||
atoi(c.getvar("expire").c_str()),
|
||||
true /* receive server reply as reply/pushover-type notification */ ))
|
||||
{
|
||||
{
|
||||
c.alert("danger", "<p class=\"lead\">Could not send test message!</p>");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// output error, return to form:
|
||||
|
@ -1156,7 +1221,7 @@ void OvmsWebServer::HandleCfgPushover(PageEntry_t& p, PageContext_t& c)
|
|||
"<td><button type=\"button\" class=\"btn btn-danger\" onclick=\"delRow(this)\"><strong>✖</strong></button></td>"
|
||||
"<td><input type=\"text\" class=\"form-control\" name=\"nfy_%d\" value=\"%s\" placeholder=\"Enter notification type/subtype\""
|
||||
" autocomplete=\"section-notification-type\"></td>"
|
||||
"<td width=\"20%\"><select class=\"form-control\" name=\"np_%d\" size=\"1\">"
|
||||
"<td width=\"20%%\"><select class=\"form-control\" name=\"np_%d\" size=\"1\">"
|
||||
, max, _attr(name)
|
||||
, max);
|
||||
gen_options_priority(kv.second);
|
||||
|
@ -2644,7 +2709,7 @@ void OvmsWebServer::HandleCfgFirmware(PageEntry_t& p, PageContext_t& c)
|
|||
c.print(
|
||||
"<datalist id=\"server-list\">"
|
||||
"<option value=\"https://ovms-ota.bit-cloud.de\">"
|
||||
"<option value=\"https://api.openvehicles.com/firmware/ota\">"
|
||||
"<option value=\"https://ovms-ota.bit-cloud.de\">"
|
||||
"<option value=\"https://ovms.dexters-web.de/firmware/ota\">"
|
||||
"</datalist>"
|
||||
"<datalist id=\"tag-list\">"
|
||||
|
@ -3924,7 +3989,7 @@ void OvmsWebServer::HandleEditor(PageEntry_t& p, PageContext_t& c)
|
|||
"text-align: center !important;\n"
|
||||
"}\n"
|
||||
"}\n"
|
||||
".log { font-size: 87%; color: gray; }\n"
|
||||
".log { font-size: 87%%; color: gray; }\n"
|
||||
".log.log-I { color: green; }\n"
|
||||
".log.log-W { color: darkorange; }\n"
|
||||
".log.log-E { color: red; }\n"
|
||||
|
|
|
@ -846,7 +846,7 @@ std::string OvmsWebServer::CfgInit3(PageEntry_t& p, PageContext_t& c, std::strin
|
|||
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");
|
||||
"https://ovms-ota.bit-cloud.de" , server == "https://ovms-ota.bit-cloud.de");
|
||||
c.input_radio_option("server", "Europe (dexters-web.de)",
|
||||
"https://ovms.dexters-web.de/firmware/ota", server == "https://ovms.dexters-web.de/firmware/ota");
|
||||
c.input_radio_end();
|
||||
|
@ -885,7 +885,7 @@ std::string OvmsWebServer::CfgInit3(PageEntry_t& p, PageContext_t& c, std::strin
|
|||
std::string OvmsWebServer::CfgInit4(PageEntry_t& p, PageContext_t& c, std::string step)
|
||||
{
|
||||
std::string error, info;
|
||||
std::string vehicletype, units_distance;
|
||||
std::string vehicletype, units_distance, units_temp, units_pressure;
|
||||
std::string server, vehicleid, password;
|
||||
|
||||
if (c.method == "POST") {
|
||||
|
@ -905,6 +905,8 @@ std::string OvmsWebServer::CfgInit4(PageEntry_t& p, PageContext_t& c, std::strin
|
|||
// process form input:
|
||||
vehicletype = c.getvar("vehicletype");
|
||||
units_distance = c.getvar("units_distance");
|
||||
units_temp = c.getvar("units_temp");
|
||||
units_pressure = c.getvar("units_pressure");
|
||||
server = c.getvar("server");
|
||||
vehicleid = c.getvar("vehicleid");
|
||||
password = c.getvar("password");
|
||||
|
@ -917,7 +919,22 @@ std::string OvmsWebServer::CfgInit4(PageEntry_t& p, PageContext_t& c, std::strin
|
|||
error += "<li data-input=\"vehicleid\">Vehicle ID may only contain ASCII letters, digits and '-'</li>";
|
||||
|
||||
// configure vehicle:
|
||||
MyConfig.SetParamValue("vehicle", "units.distance", units_distance);
|
||||
OvmsMetricSetUserConfig(GrpDistance, units_distance);
|
||||
if (units_distance == "miles") {
|
||||
OvmsMetricSetUserConfig(GrpDistanceShort, "feet");
|
||||
OvmsMetricSetUserConfig(GrpSpeed, "miph");
|
||||
OvmsMetricSetUserConfig(GrpAccel, "miphps");
|
||||
OvmsMetricSetUserConfig(GrpAccelShort, "ftpss");
|
||||
OvmsMetricSetUserConfig(GrpConsumption, "mipkwh");
|
||||
} else {
|
||||
// Set to their defaults.
|
||||
OvmsMetricSetUserConfig(GrpDistanceShort, "");
|
||||
OvmsMetricSetUserConfig(GrpSpeed, "");
|
||||
OvmsMetricSetUserConfig(GrpAccel, "");
|
||||
OvmsMetricSetUserConfig(GrpAccelShort, "");
|
||||
OvmsMetricSetUserConfig(GrpConsumption, "");
|
||||
}
|
||||
|
||||
MyConfig.SetParamValue("auto", "vehicle.type", vehicletype);
|
||||
|
||||
// configure server:
|
||||
|
@ -945,7 +962,10 @@ std::string OvmsWebServer::CfgInit4(PageEntry_t& p, PageContext_t& c, std::strin
|
|||
// read configuration:
|
||||
vehicleid = MyConfig.GetParamValue("vehicle", "id");
|
||||
vehicletype = MyConfig.GetParamValue("auto", "vehicle.type");
|
||||
units_distance = MyConfig.GetParamValue("vehicle", "units.distance", "K");
|
||||
units_distance = OvmsMetricGetUserConfig(GrpDistance);
|
||||
units_temp = OvmsMetricGetUserConfig(GrpTemp);
|
||||
units_pressure = OvmsMetricGetUserConfig(GrpPressure);
|
||||
|
||||
server = MyConfig.GetParamValue("server.v2", "server");
|
||||
password = MyConfig.GetParamValue("password","server.v2");
|
||||
|
||||
|
@ -1029,9 +1049,22 @@ std::string OvmsWebServer::CfgInit4(PageEntry_t& p, PageContext_t& c, std::strin
|
|||
c.input_select_option(k->second.name, k->first, (vehicletype == k->first));
|
||||
c.input_select_end();
|
||||
|
||||
c.input_radiobtn_start("Distance units", "units_distance");
|
||||
c.input_radiobtn_option("units_distance", "Kilometers", "K", units_distance == "K");
|
||||
c.input_radiobtn_option("units_distance", "Miles", "M", units_distance == "M");
|
||||
bool is_metric = units_distance != "miles";
|
||||
c.input_radiobtn_start("Distance related units", "units_distance");
|
||||
c.input_radiobtn_option("units_distance", "Metric (km & metres)", "", is_metric);
|
||||
c.input_radiobtn_option("units_distance", "Imperial (miles & feet)", "miles", !is_metric);
|
||||
c.input_radiobtn_end();
|
||||
|
||||
is_metric = units_temp != "fahrenheit";
|
||||
c.input_radiobtn_start("Temperature units", "units_temp");
|
||||
c.input_radiobtn_option("units_temp", "Metric (°C)", "", is_metric);
|
||||
c.input_radiobtn_option("units_temp", "Imperial (°F)", "fahrenheit", !is_metric);
|
||||
c.input_radiobtn_end();
|
||||
|
||||
is_metric = units_pressure != "psi";
|
||||
c.input_radiobtn_start("Pressure units", "units_pressure");
|
||||
c.input_radiobtn_option("units_pressure", "Metric (kPa)", "", is_metric);
|
||||
c.input_radiobtn_option("units_pressure", "Imperial (PSI)", "psi", !is_metric);
|
||||
c.input_radiobtn_end();
|
||||
|
||||
c.input_radio_start("OVMS data server", "server");
|
||||
|
|
|
@ -305,7 +305,7 @@ void OvmsWebServer::HandleDashboard(PageEntry_t& p, PageContext_t& c)
|
|||
"</div>"
|
||||
"<div class=\"underlay\">"
|
||||
"<div class=\"voltage-value\"><span class=\"value\">0</span></div>"
|
||||
"<div class=\"soc-value\"><span class=\"value\">0</span></div>"
|
||||
"<div class=\"soc-value\"><span class=\"value\">0</span><span class=\"unit\">%</span></div>"
|
||||
"<div class=\"consumption-value\"><span class=\"value\">0</span></div>"
|
||||
"<div class=\"power-value\"><span class=\"value\">0</span></div>"
|
||||
"</div>"
|
||||
|
@ -320,29 +320,29 @@ void OvmsWebServer::HandleDashboard(PageEntry_t& p, PageContext_t& c)
|
|||
"var gaugeset1;"
|
||||
""
|
||||
"function get_dashboard_data() {"
|
||||
"var rmin = metrics[\"v.b.range.est\"]||0, rmax = metrics[\"v.b.range.ideal\"]||0;\n"
|
||||
"var euse = metrics[\"v.b.energy.used\"]||0, erec = metrics[\"v.b.energy.recd\"]||0;\n"
|
||||
"var voltage = metrics[\"v.b.voltage\"]||0, soc = metrics[\"v.b.soc\"]||0;\n"
|
||||
"var consumption = metrics[\"v.b.consumption\"]||0, power = metrics[\"v.b.power\"]||0;\n"
|
||||
"var rmin = metrics_user[\"v.b.range.est\"]||0, rmax = metrics_user[\"v.b.range.ideal\"]||0;\n"
|
||||
"var euse = metrics_user[\"v.b.energy.used\"]||0, erec = metrics_user[\"v.b.energy.recd\"]||0;\n"
|
||||
"var voltage = metrics[\"v.b.voltage\"]||0, soc = metrics_user[\"v.b.soc\"]||0;\n"
|
||||
"var consumption = metrics_user[\"v.b.consumption\"]||0, power = metrics_user[\"v.b.power\"]||0;\n"
|
||||
"euse = Math.floor(euse*10)/10; erec = Math.floor(erec*10)/10;"
|
||||
"if (rmin > rmax) { var x = rmin; rmin = rmax; rmax = x; }"
|
||||
"var md = {"
|
||||
"range: { value: \"▼\" + rmin.toFixed(0) + \" ▲\" + rmax.toFixed(0) },"
|
||||
"energy: { value: \"▲\" + euse.toFixed(1) + \" ▼\" + erec.toFixed(1) },"
|
||||
"range: { value: \"▼\" + rmin.toFixed(0) + \" ▲\" + rmax.toFixed(0), unit: metrics_label[\"v.b.range.est\"] },"
|
||||
"energy: { value: \"▲\" + euse.toFixed(1) + \" ▼\" + erec.toFixed(1), unit: metrics_label[\"v.b.energy.used\"] },"
|
||||
"voltage: { value: voltage.toFixed(0) },"
|
||||
"soc: { value: soc.toFixed(0) },"
|
||||
"consumption: { value: consumption.toFixed(0) },"
|
||||
"power: { value: power.toFixed(0) },"
|
||||
"soc: { value: soc.toFixed(0), unit: metrics_label[\"v.b.soc\"] },"
|
||||
"consumption: { value: consumption.toFixed(0), unit: metrics_label[\"v.b.consumption\"] },"
|
||||
"power: { value: power.toFixed(0), unit: metrics_label[\"v.b.power\"] },"
|
||||
"series: ["
|
||||
"{ data: [metrics[\"v.p.speed\"]] },"
|
||||
"{ data: [metrics_user[\"v.p.speed\"]] },"
|
||||
"{ data: [metrics[\"v.b.voltage\"]] },"
|
||||
"{ data: [metrics[\"v.b.soc\"]] },"
|
||||
"{ data: [metrics[\"v.b.consumption\"]] },"
|
||||
"{ data: [metrics[\"v.b.power\"]] },"
|
||||
"{ data: [metrics[\"v.c.temp\"]] },"
|
||||
"{ data: [metrics[\"v.b.temp\"]] },"
|
||||
"{ data: [metrics[\"v.i.temp\"]] },"
|
||||
"{ data: [metrics[\"v.m.temp\"]] }],"
|
||||
"{ data: [metrics_user[\"v.b.soc\"]] },"
|
||||
"{ data: [metrics_user[\"v.b.consumption\"]] },"
|
||||
"{ data: [metrics_user[\"v.b.power\"]] },"
|
||||
"{ data: [metrics_user[\"v.c.temp\"]] },"
|
||||
"{ data: [metrics_user[\"v.b.temp\"]] },"
|
||||
"{ data: [metrics_user[\"v.i.temp\"]] },"
|
||||
"{ data: [metrics_user[\"v.m.temp\"]] }],"
|
||||
"};"
|
||||
"return md;"
|
||||
"}"
|
||||
|
@ -350,9 +350,12 @@ void OvmsWebServer::HandleDashboard(PageEntry_t& p, PageContext_t& c)
|
|||
"function update_dashboard() {"
|
||||
"var md = get_dashboard_data();"
|
||||
"$('.range-value .value').text(md.range.value);"
|
||||
"$('.range-value .unit').text(md.range.unit);"
|
||||
"$('.energy-value .value').text(md.energy.value);"
|
||||
"$('.energy-value .unit').text(md.energy.unit);"
|
||||
"$('.voltage-value .value').text(md.voltage.value);"
|
||||
"$('.soc-value .value').text(md.soc.value);"
|
||||
"$('.soc-value .unit').text(md.soc.unit);"
|
||||
"$('.consumption-value .value').text(md.consumption.value);"
|
||||
"$('.power-value .value').text(md.power.value);"
|
||||
"gaugeset1.update({ series: md.series });"
|
||||
|
@ -534,7 +537,7 @@ void OvmsWebServer::HandleDashboard(PageEntry_t& p, PageContext_t& c)
|
|||
""
|
||||
"/* Inject vehicle config: */"
|
||||
"for (var i = 0; i < chart_config.yAxis.length; i++) {"
|
||||
"$.extend(chart_config.yAxis[i], vehicle_config.yAxis[i]);"
|
||||
"$.extend(true, chart_config.yAxis[i], vehicle_config.yAxis[i]);"
|
||||
"}"
|
||||
""
|
||||
"gaugeset1 = Highcharts.chart('gaugeset1', chart_config,"
|
||||
|
@ -1010,7 +1013,7 @@ void OvmsWebServer::HandleBmsCellMonitor(PageEntry_t& p, PageContext_t& c)
|
|||
"});\n"
|
||||
"}\n"
|
||||
"},\n"
|
||||
"zoomType: 'y',\n"
|
||||
"zoomType: 'xy',\n"
|
||||
"panning: true,\n"
|
||||
"panKey: 'ctrl',\n"
|
||||
"},\n"
|
||||
|
@ -1088,20 +1091,20 @@ void OvmsWebServer::HandleBmsCellMonitor(PageEntry_t& p, PageContext_t& c)
|
|||
"// get_temp_data: build boxplot dataset from metrics\n"
|
||||
"function get_temp_data() {\n"
|
||||
"var data = { cells: [], temps: [], devmax: [], tempmean: 0, sdlo: 0, sdhi: 0, sdmaxlo: 0, sdmaxhi: 0 };\n"
|
||||
"var cnt = metrics[\"v.b.c.temp\"] ? metrics[\"v.b.c.temp\"].length : 0;\n"
|
||||
"var cnt = metrics_user[\"v.b.c.temp\"] ? metrics_user[\"v.b.c.temp\"].length : 0;\n"
|
||||
"if (cnt == 0)\n"
|
||||
"return data;\n"
|
||||
"var i, act, min, max, devmax, dalert, dlow, dhigh;\n"
|
||||
"data.tempmean = metrics[\"v.b.p.temp.avg\"] || 0;\n"
|
||||
"data.sdlo = data.tempmean - (metrics[\"v.b.p.temp.stddev\"] || 0);\n"
|
||||
"data.sdhi = data.tempmean + (metrics[\"v.b.p.temp.stddev\"] || 0);\n"
|
||||
"data.sdmaxlo = data.tempmean - (metrics[\"v.b.p.temp.stddev.max\"] || 0);\n"
|
||||
"data.sdmaxhi = data.tempmean + (metrics[\"v.b.p.temp.stddev.max\"] || 0);\n"
|
||||
"data.tempmean = metrics_user[\"v.b.p.temp.avg\"] || 0;\n"
|
||||
"data.sdlo = data.tempmean - (metrics_user[\"v.b.p.temp.stddev\"] || 0);\n"
|
||||
"data.sdhi = data.tempmean + (metrics_user[\"v.b.p.temp.stddev\"] || 0);\n"
|
||||
"data.sdmaxlo = data.tempmean - (metrics_user[\"v.b.p.temp.stddev.max\"] || 0);\n"
|
||||
"data.sdmaxhi = data.tempmean + (metrics_user[\"v.b.p.temp.stddev.max\"] || 0);\n"
|
||||
"for (i=0; i<cnt; i++) {\n"
|
||||
"act = metrics[\"v.b.c.temp\"][i];\n"
|
||||
"min = metrics[\"v.b.c.temp.min\"][i] || act;\n"
|
||||
"max = metrics[\"v.b.c.temp.max\"][i] || act;\n"
|
||||
"devmax = metrics[\"v.b.c.temp.dev.max\"][i] || 0;\n"
|
||||
"act = metrics_user[\"v.b.c.temp\"][i];\n"
|
||||
"min = metrics_user[\"v.b.c.temp.min\"][i] || act;\n"
|
||||
"max = metrics_user[\"v.b.c.temp.max\"][i] || act;\n"
|
||||
"devmax = metrics_user[\"v.b.c.temp.dev.max\"][i] || 0;\n"
|
||||
"dalert = metrics[\"v.b.c.temp.alert\"][i] || 0;\n"
|
||||
"if (devmax > 0) {\n"
|
||||
"dlow = data.tempmean;\n"
|
||||
|
@ -1150,7 +1153,7 @@ void OvmsWebServer::HandleBmsCellMonitor(PageEntry_t& p, PageContext_t& c)
|
|||
"});\n"
|
||||
"}\n"
|
||||
"},\n"
|
||||
"zoomType: 'y',\n"
|
||||
"zoomType: 'xy',\n"
|
||||
"panning: true,\n"
|
||||
"panKey: 'ctrl',\n"
|
||||
"},\n"
|
||||
|
|
|
@ -49,22 +49,32 @@
|
|||
* & → &
|
||||
*/
|
||||
std::string PageContext::encode_html(const char* text) {
|
||||
std::string buf;
|
||||
for (int i=0; i<strlen(text); i++) {
|
||||
if (text[i] == '\"')
|
||||
buf += """;
|
||||
else if (text[i] == '\'')
|
||||
buf += "'";
|
||||
else if(text[i] == '<')
|
||||
buf += "<";
|
||||
else if(text[i] == '>')
|
||||
buf += ">";
|
||||
else if(text[i] == '&')
|
||||
buf += "&";
|
||||
else
|
||||
buf += text[i];
|
||||
int len = strlen(text);
|
||||
std::string buf;
|
||||
buf.reserve(len);
|
||||
for (int i=0; i < len; i++) {
|
||||
char ch = text[i];
|
||||
switch(ch) {
|
||||
case '\"':
|
||||
buf.append(""");
|
||||
break;
|
||||
case '\'':
|
||||
buf.append("'");
|
||||
break;
|
||||
case '<':
|
||||
buf.append("<");
|
||||
break;
|
||||
case '>':
|
||||
buf.append(">");
|
||||
break;
|
||||
case '&':
|
||||
buf.append("&");
|
||||
break;
|
||||
default:
|
||||
buf.append(&ch,1);
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string PageContext::encode_html(std::string text) {
|
||||
|
@ -72,23 +82,31 @@ std::string PageContext::encode_html(std::string text) {
|
|||
}
|
||||
|
||||
extram::string PageContext::encode_html(const extram::string& text) {
|
||||
extram::string buf;
|
||||
extram::string buf;
|
||||
buf.reserve(text.length() + 500);
|
||||
for (int i=0; i<text.length(); i++) {
|
||||
if (text[i] == '\"')
|
||||
buf += """;
|
||||
else if (text[i] == '\'')
|
||||
buf += "'";
|
||||
else if(text[i] == '<')
|
||||
buf += "<";
|
||||
else if(text[i] == '>')
|
||||
buf += ">";
|
||||
else if(text[i] == '&')
|
||||
buf += "&";
|
||||
else
|
||||
buf += text[i];
|
||||
for (int i=0; i<text.length(); i++) {
|
||||
char ch = text[i];
|
||||
switch (ch) {
|
||||
case '\"':
|
||||
buf.append(""");
|
||||
break;
|
||||
case '\'':
|
||||
buf.append("'");
|
||||
break;
|
||||
case '<':
|
||||
buf.append("<");
|
||||
break;
|
||||
case '>':
|
||||
buf.append(">");
|
||||
break;
|
||||
case '&':
|
||||
buf.append("&");
|
||||
break;
|
||||
default:
|
||||
buf.append(&ch,1);
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
#define _attr(text) (encode_html(text).c_str())
|
||||
|
@ -102,11 +120,12 @@ extram::string PageContext::encode_html(const extram::string& text) {
|
|||
*
|
||||
*/
|
||||
std::string PageContext::make_id(const char* text) {
|
||||
std::string buf;
|
||||
std::string buf;
|
||||
char lc = 0;
|
||||
for (int i=0; i<strlen(text); i++) {
|
||||
if (isalnum(text[i]))
|
||||
buf += (lc = tolower(text[i]));
|
||||
int len = strlen(text);
|
||||
for (int i=0; i<len; i++) {
|
||||
if (isalnum(text[i]))
|
||||
buf += (lc = tolower(text[i]));
|
||||
else if (lc && lc != '-')
|
||||
buf += (lc = '-');
|
||||
}
|
||||
|
@ -114,7 +133,7 @@ std::string PageContext::make_id(const char* text) {
|
|||
lc = buf.back();
|
||||
buf.pop_back();
|
||||
}
|
||||
return buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string PageContext::make_id(std::string text) {
|
||||
|
@ -361,7 +380,7 @@ void PageContext::input_slider(const char* label, const char* name, int size, co
|
|||
"<label class=\"control-label col-sm-3\" for=\"input-%s\">%s:</label>"
|
||||
"<div class=\"col-sm-9\">"
|
||||
"<div class=\"form-control slider\" data-default=\"%g\" data-reset=\"false\""
|
||||
" data-value=\"%g\" data-min=\"%g\" data-max=\"%g\" data-step=\"%g\">"
|
||||
" data-value=\"%g\" data-min=\"%g\" data-max=\"%g\" data-step=\"%g\" data-checked=\"%s\">"
|
||||
"<div class=\"slider-control form-inline\">"
|
||||
"<input class=\"slider-enable\" type=\"%s\" %s> "
|
||||
"<input class=\"form-control slider-value\" %s type=\"number\" style=\"width:%dpx;\""
|
||||
|
@ -380,6 +399,7 @@ void PageContext::input_slider(const char* label, const char* name, int size, co
|
|||
, _attr(name)
|
||||
, label
|
||||
, defval, value, min, max, step
|
||||
, (enabled != 0) ? "true" : "false"
|
||||
, (enabled < 0) ? "hidden" : "checkbox" // -1 => no checkbox
|
||||
, (enabled > 0) ? "checked" : ""
|
||||
, (enabled == 0) ? "disabled" : ""
|
||||
|
@ -714,7 +734,8 @@ void OvmsWebServer::OutputReboot(PageEntry_t& p, PageContext_t& c)
|
|||
/**
|
||||
* OutputReconnect: output reconnect script
|
||||
*/
|
||||
void OvmsWebServer::OutputReconnect(PageEntry_t& p, PageContext_t& c, const char* info /*=NULL*/)
|
||||
void OvmsWebServer::OutputReconnect(PageEntry_t& p, PageContext_t& c, const char* info /*=NULL*/,
|
||||
const char* cmd /*=NULL*/)
|
||||
{
|
||||
c.printf(
|
||||
"<div class=\"alert alert-warning\">"
|
||||
|
@ -733,8 +754,16 @@ void OvmsWebServer::OutputReconnect(PageEntry_t& p, PageContext_t& c, const char
|
|||
"$(\"#dots\").append(\"•\");"
|
||||
"}"
|
||||
"}, 1000);"
|
||||
"</script>"
|
||||
, info ? info : "Reconnecting…");
|
||||
|
||||
if (cmd) {
|
||||
c.printf(
|
||||
"loadcmd(\"%s\");"
|
||||
, __attr(cmd));
|
||||
}
|
||||
|
||||
c.print(
|
||||
"</script>");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ void pushover_send_message(int verbosity, OvmsWriter* writer, OvmsCommand* cmd,
|
|||
sound = "pushover";
|
||||
}
|
||||
|
||||
writer->printf("Sending PUSHOVER message \"%s\" with priority %d and sound %s\n",argv[0],priority,sound);
|
||||
writer->printf("Sending PUSHOVER message \"%s\" with priority %d and sound %s\n",argv[0],priority,sound.c_str());
|
||||
MyPushoverClient.SendMessage(argv[0], priority, sound);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,4 +6,4 @@ PID SCAN
|
|||
Vehicle Type: **PID**
|
||||
|
||||
This is a research module that allows developers to scan an ECU for PIDs that respond
|
||||
with a valid reply to an extended OBDII query. It is not made to me functional.
|
||||
with a valid reply to an extended OBDII query. It is not made to be functional.
|
||||
|
|
|
@ -199,7 +199,7 @@ void scanStart(int, OvmsWriter* writer, OvmsCommand*, int argc, const char* cons
|
|||
if (start > end)
|
||||
{
|
||||
writer->printf(
|
||||
"Error: Invalid Start PID %04x is after End PID %04x\n", start, end
|
||||
"Error: Invalid Start PID %04lx is after End PID %04lx\n", start, end
|
||||
);
|
||||
valid = false;
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ void scanStart(int, OvmsWriter* writer, OvmsCommand*, int argc, const char* cons
|
|||
}
|
||||
if (POLL_TYPE_HAS_8BIT_PID(polltype) && end > 0xff)
|
||||
{
|
||||
writer->printf("Error: Poll type %x PID range is 00..ff\n");
|
||||
writer->printf("Error: Poll type %lx PID range is 00..ff\n", polltype);
|
||||
valid = false;
|
||||
}
|
||||
if (!valid)
|
||||
|
@ -229,7 +229,7 @@ void scanStart(int, OvmsWriter* writer, OvmsCommand*, int argc, const char* cons
|
|||
if (valid)
|
||||
{
|
||||
s_scanner = new OvmsReToolsPidScanner(can, ecu, rxid_low, rxid_high, polltype, start, end, step, timeout);
|
||||
writer->printf("Scan started: bus %d, ecu %x, rxid %x-%x, polltype %x, PID %x-%x (step %x), timeout %d seconds\n",
|
||||
writer->printf("Scan started: bus %ld, ecu %lx, rxid %lx-%lx, polltype %lx, PID %lx-%lx (step %lx), timeout %d seconds\n",
|
||||
bus, ecu, rxid_low, rxid_high, polltype, start, end, step, timeout);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,13 +97,13 @@ static void IRAM_ATTR sdcard_isr_handler(void* arg)
|
|||
sdcard::sdcard(const char* name, bool mode1bit, bool autoformat, int cdpin)
|
||||
: pcp(name)
|
||||
{
|
||||
m_host = SDMMC_HOST_DEFAULT();
|
||||
m_host = sdmmc_host_t SDMMC_HOST_DEFAULT();
|
||||
if (mode1bit)
|
||||
{
|
||||
m_host.flags = SDMMC_HOST_FLAG_1BIT;
|
||||
}
|
||||
|
||||
m_slot = SDMMC_SLOT_CONFIG_DEFAULT();
|
||||
m_slot = sdmmc_slot_config_t SDMMC_SLOT_CONFIG_DEFAULT();
|
||||
// Disable driver-level CD pin, as we do this ourselves
|
||||
// if (cdpin)
|
||||
// {
|
||||
|
|
|
@ -69,17 +69,43 @@ const char* simcom5360::GetName()
|
|||
void simcom5360::StatusPoller()
|
||||
{
|
||||
if (m_modem->m_mux != NULL)
|
||||
{ m_modem->muxtx(GetMuxChannelPOLL(), "AT+CREG?;+CCLK?;+CSQ;+CPSI?;+COPS?\r\n"); }
|
||||
{
|
||||
// The ESP32 UART queue has a capacity of 128 bytes, NMEA and PPP data may be
|
||||
// coming in concurrently, and we cannot use flow control.
|
||||
// Reduce the queue stress by distributing the status poll:
|
||||
switch (++m_statuspoller_step)
|
||||
{
|
||||
case 1:
|
||||
m_modem->muxtx(GetMuxChannelPOLL(), "AT+CREG?;+CCLK?;+CSQ\r\n");
|
||||
// → ~ 55 bytes, e.g.
|
||||
// +CREG: 1,5 +CCLK: "22/10/02,09:33:27+08" +CSQ: 24,99
|
||||
break;
|
||||
case 2:
|
||||
m_modem->muxtx(GetMuxChannelPOLL(), "AT+CPSI?\r\n");
|
||||
// → ~ 60 bytes, e.g.
|
||||
// +CPSI: GSM,Online,262-02,0x011f,14822,4 EGSM 900,-67,0,40-40
|
||||
break;
|
||||
case 3:
|
||||
m_modem->muxtx(GetMuxChannelPOLL(), "AT+COPS?\r\n");
|
||||
// → ~ 35 bytes, e.g.
|
||||
// +COPS: 0,0,"vodafone.de Hologram",0
|
||||
|
||||
// done, fallthrough:
|
||||
default:
|
||||
m_statuspoller_step = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool simcom5360::State1Leave(modem::modem_state1_t oldstate)
|
||||
{
|
||||
return false;
|
||||
return modemdriver::State1Leave(oldstate);
|
||||
}
|
||||
|
||||
bool simcom5360::State1Enter(modem::modem_state1_t newstate)
|
||||
{
|
||||
return false;
|
||||
return modemdriver::State1Enter(newstate);
|
||||
}
|
||||
|
||||
modem::modem_state1_t simcom5360::State1Activity(modem::modem_state1_t curstate)
|
||||
|
@ -93,7 +119,7 @@ modem::modem_state1_t simcom5360::State1Activity(modem::modem_state1_t curstate)
|
|||
return modem::None;
|
||||
}
|
||||
|
||||
return curstate;
|
||||
return modemdriver::State1Activity(curstate);
|
||||
}
|
||||
|
||||
modem::modem_state1_t simcom5360::State1Ticker1(modem::modem_state1_t curstate)
|
||||
|
@ -125,11 +151,13 @@ modem::modem_state1_t simcom5360::State1Ticker1(modem::modem_state1_t curstate)
|
|||
m_modem->tx("AT+CMUXSRVPORT=0,5\r\n");
|
||||
break;
|
||||
case 20:
|
||||
m_modem->tx("AT+CMUX=0\r\n");
|
||||
// start MUX mode, route URCs to MUX channel 3 (POLL)
|
||||
// Note: NMEA URCs will still be sent only on channel 1 (NMEA) by the SIMCOM 5360
|
||||
m_modem->tx("AT+CMUX=0;+CATR=6\r\n");
|
||||
break;
|
||||
}
|
||||
return modem::None;
|
||||
}
|
||||
|
||||
return curstate;
|
||||
return modemdriver::State1Ticker1(curstate);
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ void simcom7000::PowerCycle()
|
|||
m_powercyclefactor = m_powercyclefactor % 3;
|
||||
ESP_LOGI(TAG, "Power Cycle (SIM7000) %dms",psd);
|
||||
|
||||
uart_wait_tx_done(m_modem->m_uartnum, portMAX_DELAY);
|
||||
uart_flush(m_modem->m_uartnum); // Flush the ring buffer, to try to address MUX start issues
|
||||
#ifdef CONFIG_OVMS_COMP_MAX7317
|
||||
MyPeripherals->m_max7317->Output(MODEM_EGPIO_PWR, 0); // Modem EN/PWR line low
|
||||
|
@ -125,7 +126,8 @@ modem::modem_state1_t simcom7000::State1Ticker1(modem::modem_state1_t curstate)
|
|||
m_modem->tx("AT+CGMR;+ICCID\r\n");
|
||||
break;
|
||||
case 20:
|
||||
m_modem->tx("AT+CMUX=0\r\n");
|
||||
// start MUX mode, route URCs to MUX channel 3 (POLL)
|
||||
m_modem->tx("AT+CMUX=0;+CATR=6\r\n");
|
||||
break;
|
||||
}
|
||||
return modem::None;
|
||||
|
|
|
@ -80,6 +80,7 @@ void simcom7600::StartupNMEA()
|
|||
{
|
||||
m_modem->muxtx(GetMuxChannelCMD(), "AT+CGPS=0\r\n");
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
// send single commands, as each can fail:
|
||||
m_modem->muxtx(GetMuxChannelCMD(), "AT+CGPSNMEA=258\r\n");
|
||||
m_modem->muxtx(GetMuxChannelCMD(), "AT+CGPSINFOCFG=5,258\r\n");
|
||||
m_modem->muxtx(GetMuxChannelCMD(), "AT+CGPS=1,1\r\n");
|
||||
|
@ -88,10 +89,51 @@ void simcom7600::StartupNMEA()
|
|||
{ ESP_LOGE(TAG, "Attempt to transmit on non running mux"); }
|
||||
}
|
||||
|
||||
void simcom7600::ShutdownNMEA()
|
||||
{
|
||||
// Switch off GPS:
|
||||
if (m_modem->m_mux != NULL)
|
||||
{
|
||||
// send single commands, as each can fail:
|
||||
m_modem->muxtx(GetMuxChannelCMD(), "AT+CGPSNMEA=0\r\n");
|
||||
m_modem->muxtx(GetMuxChannelCMD(), "AT+CGPSINFOCFG=0\r\n");
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
m_modem->muxtx(GetMuxChannelCMD(), "AT+CGPS=0\r\n");
|
||||
}
|
||||
else
|
||||
{ ESP_LOGE(TAG, "Attempt to transmit on non running mux"); }
|
||||
}
|
||||
|
||||
void simcom7600::StatusPoller()
|
||||
{
|
||||
if (m_modem->m_mux != NULL)
|
||||
{ m_modem->muxtx(GetMuxChannelPOLL(), "AT+CREG?;+CCLK?;+CSQ;+CPSI?;+COPS?\r\n"); }
|
||||
{
|
||||
// The ESP32 UART queue has a capacity of 128 bytes, NMEA and PPP data may be
|
||||
// coming in concurrently, and we cannot use flow control.
|
||||
// Reduce the queue stress by distributing the status poll:
|
||||
switch (++m_statuspoller_step)
|
||||
{
|
||||
case 1:
|
||||
m_modem->muxtx(GetMuxChannelPOLL(), "AT+CREG?;+CGREG?;+CEREG?;+CCLK?;+CSQ\r\n");
|
||||
// → ~ 80 bytes, e.g.
|
||||
// +CREG: 1,5 +CGREG: 1,5 +CEREG: 1,5 +CCLK: "22/09/09,12:54:41+08" +CSQ: 13,99
|
||||
break;
|
||||
case 2:
|
||||
m_modem->muxtx(GetMuxChannelPOLL(), "AT+CPSI?\r\n");
|
||||
// → ~ 85 bytes, e.g.
|
||||
// +CPSI: LTE,Online,262-02,0xB0F5,13179412,448,EUTRAN-BAND1,100,4,4,-122,-1184,-874,9
|
||||
break;
|
||||
case 3:
|
||||
m_modem->muxtx(GetMuxChannelPOLL(), "AT+COPS?\r\n");
|
||||
// → ~ 35 bytes, e.g.
|
||||
// +COPS: 0,0,"vodafone.de Hologram",7
|
||||
|
||||
// done, fallthrough:
|
||||
default:
|
||||
m_statuspoller_step = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void simcom7600::PowerCycle()
|
||||
|
@ -100,6 +142,7 @@ void simcom7600::PowerCycle()
|
|||
m_powercyclefactor = m_powercyclefactor % 3;
|
||||
ESP_LOGI(TAG, "Power Cycle (SIM7600) %dms",psd);
|
||||
|
||||
uart_wait_tx_done(m_modem->m_uartnum, portMAX_DELAY);
|
||||
uart_flush(m_modem->m_uartnum); // Flush the ring buffer, to try to address MUX start issues
|
||||
#ifdef CONFIG_OVMS_COMP_MAX7317
|
||||
MyPeripherals->m_max7317->Output(MODEM_EGPIO_PWR, 0); // Modem EN/PWR line low
|
||||
|
@ -111,12 +154,12 @@ void simcom7600::PowerCycle()
|
|||
|
||||
bool simcom7600::State1Leave(modem::modem_state1_t oldstate)
|
||||
{
|
||||
return false;
|
||||
return modemdriver::State1Leave(oldstate);
|
||||
}
|
||||
|
||||
bool simcom7600::State1Enter(modem::modem_state1_t newstate)
|
||||
{
|
||||
return false;
|
||||
return modemdriver::State1Enter(newstate);
|
||||
}
|
||||
|
||||
modem::modem_state1_t simcom7600::State1Activity(modem::modem_state1_t curstate)
|
||||
|
@ -130,7 +173,7 @@ modem::modem_state1_t simcom7600::State1Activity(modem::modem_state1_t curstate)
|
|||
return modem::None;
|
||||
}
|
||||
|
||||
return curstate;
|
||||
return modemdriver::State1Activity(curstate);
|
||||
}
|
||||
|
||||
modem::modem_state1_t simcom7600::State1Ticker1(modem::modem_state1_t curstate)
|
||||
|
@ -144,17 +187,21 @@ modem::modem_state1_t simcom7600::State1Ticker1(modem::modem_state1_t curstate)
|
|||
switch (m_modem->m_state1_ticker)
|
||||
{
|
||||
case 10:
|
||||
m_modem->tx("AT+CPIN?;+CREG=1;+CTZU=1;+CTZR=1;+CLIP=1;+CMGF=1;+CNMI=1,2,0,0,0;+CSDH=1;+CMEE=2;+CSQ;+AUTOCSQ=1,1;E0;S0=0\r\n");
|
||||
m_modem->tx("AT+CPIN?;+CREG=1;+CGREG=1;+CEREG=1;+CTZU=1;+CTZR=1;+CLIP=1;+CMGF=1;+CNMI=1,2,0,0,0;+CSDH=1;+CMEE=2;+CSQ;+AUTOCSQ=1,1;E0;S0=0\r\n");
|
||||
break;
|
||||
case 12:
|
||||
m_modem->tx("AT+CGMR;+ICCID\r\n");
|
||||
break;
|
||||
case 20:
|
||||
m_modem->tx("AT+CMUX=0\r\n");
|
||||
// start MUX mode, route URCs to MUX channel 3 (POLL)
|
||||
// Note: NMEA URCs will now also be sent on channel 3 by the SIMCOM 7600;
|
||||
// without +CATR, NMEA URCs are sent identically on all channels;
|
||||
// there is no option to route these separately to channel 1 (NMEA)
|
||||
m_modem->tx("AT+CMUX=0;+CATR=6\r\n");
|
||||
break;
|
||||
}
|
||||
return modem::None;
|
||||
}
|
||||
|
||||
return curstate;
|
||||
return modemdriver::State1Ticker1(curstate);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ class simcom7600 : public modemdriver
|
|||
int GetMuxChannelPOLL() { return 3; }
|
||||
int GetMuxChannelCMD() { return 4; }
|
||||
void StartupNMEA();
|
||||
void ShutdownNMEA();
|
||||
void StatusPoller();
|
||||
|
||||
void PowerCycle();
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
||||
|
||||
ifeq ($(shell expr $(IDF_VERSION_MAJOR) \< 4), 1)
|
||||
COMPONENT_ADD_INCLUDEDIRS:=src
|
||||
COMPONENT_SRCDIRS:=src
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
endif
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -356,6 +358,8 @@ OvmsVehicle::OvmsVehicle()
|
|||
m_brakelight_ignftbrk = false;
|
||||
|
||||
m_tpms_lastcheck = 0;
|
||||
m_inv_energyused = 0;
|
||||
m_inv_energyrecd = 0;
|
||||
|
||||
m_rxqueue = xQueueCreate(CONFIG_OVMS_VEHICLE_CAN_RX_QUEUE_SIZE,sizeof(CAN_frame_t));
|
||||
xTaskCreatePinnedToCore(OvmsVehicleRxTask, "OVMS Vehicle",
|
||||
|
@ -977,7 +981,6 @@ bool OvmsVehicle::TPMSWrite(std::vector<uint32_t> &tpms)
|
|||
*/
|
||||
OvmsVehicle::vehicle_command_t OvmsVehicle::CommandStat(int verbosity, OvmsWriter* writer)
|
||||
{
|
||||
metric_unit_t rangeUnit = (MyConfig.GetParamValue("vehicle", "units.distance") == "M") ? Miles : Kilometers;
|
||||
|
||||
bool chargeport_open = StdMetrics.ms_v_door_chargeport->AsBool();
|
||||
std::string charge_state = StdMetrics.ms_v_charge_state->AsString();
|
||||
|
@ -1028,10 +1031,9 @@ OvmsVehicle::vehicle_command_t OvmsVehicle::CommandStat(int verbosity, OvmsWrite
|
|||
}
|
||||
|
||||
// Charge speed:
|
||||
if (StdMetrics.ms_v_bat_range_speed->AsFloat() != 0)
|
||||
if (StdMetrics.ms_v_bat_range_speed->IsDefined() && StdMetrics.ms_v_bat_range_speed->AsFloat() != 0)
|
||||
{
|
||||
metric_unit_t speedUnit = (rangeUnit == Miles) ? Mph : Kph;
|
||||
writer->printf("%s\n", StdMetrics.ms_v_bat_range_speed->AsUnitString("-", speedUnit, 1).c_str());
|
||||
writer->printf("%s\n", StdMetrics.ms_v_bat_range_speed->AsUnitString("-", ToUser, 1).c_str());
|
||||
}
|
||||
else if (show_vc)
|
||||
{
|
||||
|
@ -1046,13 +1048,13 @@ OvmsVehicle::vehicle_command_t OvmsVehicle::CommandStat(int verbosity, OvmsWrite
|
|||
int duration_soc = StdMetrics.ms_v_charge_duration_soc->AsInt();
|
||||
if (duration_soc > 0)
|
||||
writer->printf("%s: %d:%02dh\n",
|
||||
(char*) StdMetrics.ms_v_charge_limit_soc->AsUnitString("SOC", Native, 0).c_str(),
|
||||
(char*) StdMetrics.ms_v_charge_limit_soc->AsUnitString("SOC", ToUser, 0).c_str(),
|
||||
duration_soc / 60, duration_soc % 60);
|
||||
|
||||
int duration_range = StdMetrics.ms_v_charge_duration_range->AsInt();
|
||||
if (duration_range > 0)
|
||||
writer->printf("%s: %d:%02dh\n",
|
||||
(char*) StdMetrics.ms_v_charge_limit_range->AsUnitString("Range", rangeUnit, 0).c_str(),
|
||||
(char*) StdMetrics.ms_v_charge_limit_range->AsUnitString("Range", ToUser, 0).c_str(),
|
||||
duration_range / 60, duration_range % 60);
|
||||
}
|
||||
|
||||
|
@ -1060,12 +1062,12 @@ OvmsVehicle::vehicle_command_t OvmsVehicle::CommandStat(int verbosity, OvmsWrite
|
|||
if (StdMetrics.ms_v_charge_kwh_grid->IsDefined())
|
||||
{
|
||||
writer->printf("Drawn: %s\n",
|
||||
StdMetrics.ms_v_charge_kwh_grid->AsUnitString("-", Native, 1).c_str());
|
||||
StdMetrics.ms_v_charge_kwh_grid->AsUnitString("-", ToUser, 1).c_str());
|
||||
}
|
||||
if (StdMetrics.ms_v_charge_kwh->IsDefined())
|
||||
{
|
||||
writer->printf("Charged: %s\n",
|
||||
StdMetrics.ms_v_charge_kwh->AsUnitString("-", Native, 1).c_str());
|
||||
StdMetrics.ms_v_charge_kwh->AsUnitString("-", ToUser, 1).c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1073,27 +1075,37 @@ OvmsVehicle::vehicle_command_t OvmsVehicle::CommandStat(int verbosity, OvmsWrite
|
|||
writer->puts("Not charging");
|
||||
}
|
||||
|
||||
writer->printf("SOC: %s\n", (char*) StdMetrics.ms_v_bat_soc->AsUnitString("-", Native, 1).c_str());
|
||||
writer->printf("SOC: %s\n", (char*) StdMetrics.ms_v_bat_soc->AsUnitString("-", ToUser, 1).c_str());
|
||||
|
||||
const char* range_ideal = StdMetrics.ms_v_bat_range_ideal->AsUnitString("-", rangeUnit, 0).c_str();
|
||||
if (*range_ideal != '-')
|
||||
writer->printf("Ideal range: %s\n", range_ideal);
|
||||
if (StdMetrics.ms_v_bat_range_ideal->IsDefined())
|
||||
{
|
||||
const std::string& range_ideal = StdMetrics.ms_v_bat_range_ideal->AsUnitString("-", ToUser, 0);
|
||||
writer->printf("Ideal range: %s\n", range_ideal.c_str());
|
||||
}
|
||||
|
||||
const char* range_est = StdMetrics.ms_v_bat_range_est->AsUnitString("-", rangeUnit, 0).c_str();
|
||||
if (*range_est != '-')
|
||||
writer->printf("Est. range: %s\n", range_est);
|
||||
if (StdMetrics.ms_v_bat_range_est->IsDefined())
|
||||
{
|
||||
const std::string& range_est = StdMetrics.ms_v_bat_range_est->AsUnitString("-", ToUser, 0);
|
||||
writer->printf("Est. range: %s\n", range_est.c_str());
|
||||
}
|
||||
|
||||
const char* odometer = StdMetrics.ms_v_pos_odometer->AsUnitString("-", rangeUnit, 1).c_str();
|
||||
if (*odometer != '-')
|
||||
writer->printf("ODO: %s\n", odometer);
|
||||
if (StdMetrics.ms_v_pos_odometer->IsDefined())
|
||||
{
|
||||
const std::string& odometer = StdMetrics.ms_v_pos_odometer->AsUnitString("-", ToUser, 1);
|
||||
writer->printf("ODO: %s\n", odometer.c_str());
|
||||
}
|
||||
|
||||
const char* cac = StdMetrics.ms_v_bat_cac->AsUnitString("-", Native, 1).c_str();
|
||||
if (*cac != '-')
|
||||
writer->printf("CAC: %s\n", cac);
|
||||
if (StdMetrics.ms_v_bat_cac->IsDefined())
|
||||
{
|
||||
const std::string& cac = StdMetrics.ms_v_bat_cac->AsUnitString("-", ToUser, 1);
|
||||
writer->printf("CAC: %s\n", cac.c_str());
|
||||
}
|
||||
|
||||
const char* soh = StdMetrics.ms_v_bat_soh->AsUnitString("-", Native, 0).c_str();
|
||||
if (*soh != '-')
|
||||
writer->printf("SOH: %s\n", soh);
|
||||
if (StdMetrics.ms_v_bat_soh->IsDefined())
|
||||
{
|
||||
const std::string& soh = StdMetrics.ms_v_bat_soh->AsUnitString("-", ToUser, 0);
|
||||
writer->printf("SOH: %s\n", soh.c_str());
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
@ -1103,12 +1115,12 @@ OvmsVehicle::vehicle_command_t OvmsVehicle::CommandStat(int verbosity, OvmsWrite
|
|||
*/
|
||||
OvmsVehicle::vehicle_command_t OvmsVehicle::CommandStatTrip(int verbosity, OvmsWriter* writer)
|
||||
{
|
||||
metric_unit_t rangeUnit = (MyConfig.GetParamValue("vehicle", "units.distance") == "M") ? Miles : Kilometers;
|
||||
metric_unit_t speedUnit = (rangeUnit == Miles) ? Mph : Kph;
|
||||
metric_unit_t accelUnit = (rangeUnit == Miles) ? MphPS : KphPS;
|
||||
metric_unit_t consumUnit = (rangeUnit == Miles) ? WattHoursPM : WattHoursPK;
|
||||
metric_unit_t rangeUnit = OvmsMetricGetUserUnit(GrpDistance, Kilometers);
|
||||
metric_unit_t speedUnit = OvmsMetricGetUserUnit(GrpSpeed, Kph);
|
||||
metric_unit_t accelUnit = OvmsMetricGetUserUnit(GrpAccel, KphPS);
|
||||
metric_unit_t consumUnit = OvmsMetricGetUserUnit(GrpConsumption, WattHoursPK);
|
||||
metric_unit_t energyUnit = kWh;
|
||||
metric_unit_t altitudeUnit = (rangeUnit == Miles) ? Feet : Meters;
|
||||
metric_unit_t altitudeUnit = OvmsMetricGetUserUnit(GrpDistanceShort, Meters);
|
||||
const char* rangeUnitLabel = OvmsMetricUnitLabel(rangeUnit);
|
||||
const char* speedUnitLabel = OvmsMetricUnitLabel(speedUnit);
|
||||
const char* accelUnitLabel = OvmsMetricUnitLabel(accelUnit);
|
||||
|
@ -1116,7 +1128,7 @@ OvmsVehicle::vehicle_command_t OvmsVehicle::CommandStatTrip(int verbosity, OvmsW
|
|||
const char* energyUnitLabel = OvmsMetricUnitLabel(energyUnit);
|
||||
const char* altitudeUnitLabel = OvmsMetricUnitLabel(altitudeUnit);
|
||||
|
||||
float trip_length = StdMetrics.ms_v_pos_trip->AsFloat(0, rangeUnit);
|
||||
float trip_length = StdMetrics.ms_v_pos_trip->AsFloat(0);
|
||||
|
||||
float speed_avg = (m_drive_speedcnt > 0)
|
||||
? UnitConvert(Kph, speedUnit, (float)(m_drive_speedsum / m_drive_speedcnt))
|
||||
|
@ -1132,7 +1144,7 @@ OvmsVehicle::vehicle_command_t OvmsVehicle::CommandStatTrip(int verbosity, OvmsW
|
|||
float energy_used = StdMetrics.ms_v_bat_energy_used->AsFloat();
|
||||
float energy_recd = StdMetrics.ms_v_bat_energy_recd->AsFloat();
|
||||
float energy_recd_perc = (energy_used > 0) ? energy_recd / energy_used * 100 : 0;
|
||||
float wh_per_rangeunit = (trip_length > 0) ? (energy_used - energy_recd) * 1000 / trip_length : 0;
|
||||
float wh_per_km = (trip_length > 0) ? (energy_used - energy_recd) * 1000 / trip_length : 0;
|
||||
|
||||
float soc = StdMetrics.ms_v_bat_soc->AsFloat();
|
||||
float soc_diff = soc - m_drive_startsoc;
|
||||
|
@ -1146,7 +1158,7 @@ OvmsVehicle::vehicle_command_t OvmsVehicle::CommandStatTrip(int verbosity, OvmsW
|
|||
<< "Trip "
|
||||
<< std::fixed
|
||||
<< std::setprecision(1)
|
||||
<< trip_length << rangeUnitLabel
|
||||
<< UnitConvert(Kilometers, rangeUnit, trip_length) << rangeUnitLabel
|
||||
<< " Avg "
|
||||
<< std::setprecision(0)
|
||||
<< speed_avg << speedUnitLabel
|
||||
|
@ -1154,11 +1166,11 @@ OvmsVehicle::vehicle_command_t OvmsVehicle::CommandStatTrip(int verbosity, OvmsW
|
|||
<< ((alt_diff >= 0) ? "+" : "")
|
||||
<< alt_diff << altitudeUnitLabel
|
||||
;
|
||||
if (wh_per_rangeunit != 0)
|
||||
if (wh_per_km != 0)
|
||||
{
|
||||
buf
|
||||
<< "\nEnergy "
|
||||
<< wh_per_rangeunit << consumUnitLabel
|
||||
<< UnitConvert(WattHoursPK, consumUnit, wh_per_km) << consumUnitLabel
|
||||
<< ", "
|
||||
<< energy_recd_perc << "% recd"
|
||||
;
|
||||
|
@ -1490,6 +1502,12 @@ void OvmsVehicle::MetricModified(OvmsMetric* metric)
|
|||
NotifyChargeState();
|
||||
}
|
||||
}
|
||||
else if (metric == StandardMetrics.ms_v_charge_type)
|
||||
{
|
||||
std::string m = metric->AsString();
|
||||
MyEvents.SignalEvent("vehicle.charge.type", (void*)m.c_str(), m.size()+1);
|
||||
NotifiedVehicleChargeType(m);
|
||||
}
|
||||
else if (metric == StandardMetrics.ms_v_gen_state)
|
||||
{
|
||||
std::string state = metric->AsString();
|
||||
|
@ -1497,6 +1515,12 @@ void OvmsVehicle::MetricModified(OvmsMetric* metric)
|
|||
if (m_autonotifications)
|
||||
NotifyGenState();
|
||||
}
|
||||
else if (metric == StandardMetrics.ms_v_gen_type)
|
||||
{
|
||||
std::string m = metric->AsString();
|
||||
MyEvents.SignalEvent("vehicle.gen.type", (void*)m.c_str(), m.size()+1);
|
||||
NotifiedVehicleGenType(m);
|
||||
}
|
||||
else if (metric == StandardMetrics.ms_v_pos_speed)
|
||||
{
|
||||
// Collect data for trip speed average:
|
||||
|
@ -1988,68 +2012,82 @@ OvmsVehicle::vehicle_command_t OvmsVehicle::ProcessMsgCommand(std::string &resul
|
|||
*/
|
||||
void OvmsVehicle::GetDashboardConfig(DashboardConfig& cfg)
|
||||
{
|
||||
cfg.gaugeset1 =
|
||||
"yAxis: [{"
|
||||
// Speed:
|
||||
"min: 0, max: 200,"
|
||||
"plotBands: ["
|
||||
"{ from: 0, to: 120, className: 'green-band' },"
|
||||
"{ from: 120, to: 160, className: 'yellow-band' },"
|
||||
"{ from: 160, to: 200, className: 'red-band' }]"
|
||||
"},{"
|
||||
// Voltage:
|
||||
"min: 310, max: 410,"
|
||||
"plotBands: ["
|
||||
"{ from: 310, to: 325, className: 'red-band' },"
|
||||
"{ from: 325, to: 340, className: 'yellow-band' },"
|
||||
"{ from: 340, to: 410, className: 'green-band' }]"
|
||||
"},{"
|
||||
// SOC:
|
||||
"min: 0, max: 100,"
|
||||
"plotBands: ["
|
||||
"{ from: 0, to: 12.5, className: 'red-band' },"
|
||||
"{ from: 12.5, to: 25, className: 'yellow-band' },"
|
||||
"{ from: 25, to: 100, className: 'green-band' }]"
|
||||
"},{"
|
||||
// Efficiency:
|
||||
"min: 0, max: 400,"
|
||||
"plotBands: ["
|
||||
"{ from: 0, to: 200, className: 'green-band' },"
|
||||
"{ from: 200, to: 300, className: 'yellow-band' },"
|
||||
"{ from: 300, to: 400, className: 'red-band' }]"
|
||||
"},{"
|
||||
// Power:
|
||||
"min: -50, max: 200,"
|
||||
"plotBands: ["
|
||||
"{ from: -50, to: 0, className: 'violet-band' },"
|
||||
"{ from: 0, to: 100, className: 'green-band' },"
|
||||
"{ from: 100, to: 150, className: 'yellow-band' },"
|
||||
"{ from: 150, to: 200, className: 'red-band' }]"
|
||||
"},{"
|
||||
// Charger temperature:
|
||||
"min: 20, max: 80, tickInterval: 20,"
|
||||
"plotBands: ["
|
||||
"{ from: 20, to: 65, className: 'normal-band border' },"
|
||||
"{ from: 65, to: 80, className: 'red-band border' }]"
|
||||
"},{"
|
||||
// Battery temperature:
|
||||
"min: -15, max: 65, tickInterval: 25,"
|
||||
"plotBands: ["
|
||||
"{ from: -15, to: 0, className: 'red-band border' },"
|
||||
"{ from: 0, to: 50, className: 'normal-band border' },"
|
||||
"{ from: 50, to: 65, className: 'red-band border' }]"
|
||||
"},{"
|
||||
// Inverter temperature:
|
||||
"min: 20, max: 80, tickInterval: 20,"
|
||||
"plotBands: ["
|
||||
"{ from: 20, to: 70, className: 'normal-band border' },"
|
||||
"{ from: 70, to: 80, className: 'red-band border' }]"
|
||||
"},{"
|
||||
// Motor temperature:
|
||||
"min: 50, max: 125, tickInterval: 25,"
|
||||
"plotBands: ["
|
||||
"{ from: 50, to: 110, className: 'normal-band border' },"
|
||||
"{ from: 110, to: 125, className: 'red-band border' }]"
|
||||
"}]";
|
||||
// Speed:
|
||||
dash_gauge_t speed_dash(NULL,Kph);
|
||||
speed_dash.SetMinMax(0, 200, 5);
|
||||
speed_dash.AddBand("green", 0, 120);
|
||||
speed_dash.AddBand("yellow", 120, 160);
|
||||
speed_dash.AddBand("red", 160, 200);
|
||||
|
||||
// Voltage:
|
||||
dash_gauge_t voltage_dash(NULL,Volts);
|
||||
voltage_dash.SetMinMax(310, 410);
|
||||
voltage_dash.AddBand("red", 310, 325);
|
||||
voltage_dash.AddBand("yellow", 325, 340);
|
||||
voltage_dash.AddBand("green", 340, 410);
|
||||
|
||||
// SOC:
|
||||
dash_gauge_t soc_dash("SOC ",Percentage);
|
||||
soc_dash.SetMinMax(0, 100);
|
||||
soc_dash.AddBand("red", 0, 12.5);
|
||||
soc_dash.AddBand("yellow", 12.5, 25);
|
||||
soc_dash.AddBand("green", 25, 100);
|
||||
|
||||
// Efficiency:
|
||||
dash_gauge_t eff_dash(NULL,WattHoursPK);
|
||||
eff_dash.SetMinMax(0, 400);
|
||||
eff_dash.AddBand("green", 0, 200);
|
||||
eff_dash.AddBand("yellow", 200, 300);
|
||||
eff_dash.AddBand("red", 300, 400);
|
||||
|
||||
// Power:
|
||||
dash_gauge_t power_dash(NULL,kW);
|
||||
power_dash.SetMinMax(-50, 200);
|
||||
power_dash.AddBand("violet", -50, 0);
|
||||
power_dash.AddBand("green", 0, 100);
|
||||
power_dash.AddBand("yellow", 100, 150);
|
||||
power_dash.AddBand("red", 150, 200);
|
||||
|
||||
// Charger temperature:
|
||||
dash_gauge_t charget_dash("CHG ",Celcius);
|
||||
charget_dash.SetMinMax(20, 80);
|
||||
charget_dash.SetTick(20);
|
||||
charget_dash.AddBand("normal", 20, 65);
|
||||
charget_dash.AddBand("red", 65, 80);
|
||||
|
||||
// Battery temperature:
|
||||
dash_gauge_t batteryt_dash("BAT ",Celcius);
|
||||
batteryt_dash.SetMinMax(-15, 65);
|
||||
batteryt_dash.SetTick(25);
|
||||
batteryt_dash.AddBand("red", -15, 0);
|
||||
batteryt_dash.AddBand("normal", 0, 50);
|
||||
batteryt_dash.AddBand("red", 50, 65);
|
||||
|
||||
// Inverter temperature:
|
||||
dash_gauge_t invertert_dash("PEM ",Celcius);
|
||||
invertert_dash.SetMinMax(20, 80);
|
||||
invertert_dash.SetTick(20);
|
||||
invertert_dash.AddBand("normal", 20, 70);
|
||||
invertert_dash.AddBand("red", 70, 80);
|
||||
|
||||
// Motor temperature:
|
||||
dash_gauge_t motort_dash("MOT ",Celcius);
|
||||
motort_dash.SetMinMax(50, 125);
|
||||
motort_dash.SetTick(25);
|
||||
motort_dash.AddBand("normal", 50, 110);
|
||||
motort_dash.AddBand("red", 110, 125);
|
||||
|
||||
std::ostringstream str;
|
||||
str
|
||||
<< batteryt_dash // Battery temperature
|
||||
<< voltage_dash // Voltage
|
||||
<< motort_dash // Motor temperature
|
||||
<< invertert_dash // Inverter temperature
|
||||
<< power_dash // Power
|
||||
<< soc_dash // SOC
|
||||
<< charget_dash // Charger temperature
|
||||
<< speed_dash // Speed
|
||||
<< eff_dash; // Efficiency
|
||||
cfg.gaugeset1 = str.str();
|
||||
}
|
||||
#endif // #ifdef CONFIG_OVMS_COMP_WEBSERVER
|
||||
|
|
|
@ -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.
|
||||
|
@ -273,6 +275,14 @@ typedef struct
|
|||
uint32_t lastused; // Timestamp of last channel access
|
||||
} vwtp_channel_t;
|
||||
|
||||
enum class OvmsStatus : short {
|
||||
OK = 0,
|
||||
Warn = 1,
|
||||
Alert = 2
|
||||
};
|
||||
inline bool operator<(OvmsStatus lhs, OvmsStatus rhs) {
|
||||
return static_cast<short>(lhs) < static_cast<short>(rhs);
|
||||
}
|
||||
|
||||
class OvmsVehicle : public InternalRamAllocated
|
||||
{
|
||||
|
@ -437,7 +447,9 @@ class OvmsVehicle : public InternalRamAllocated
|
|||
virtual void NotifiedVehicleDrivemode(int drivemode) {}
|
||||
virtual void NotifiedVehicleChargeMode(const char* m) {}
|
||||
virtual void NotifiedVehicleChargeState(const char* s) {}
|
||||
virtual void NotifiedVehicleChargeType(const std::string& state) {}
|
||||
virtual void NotifiedVehicleGenState(const std::string& state) {}
|
||||
virtual void NotifiedVehicleGenType(const std::string& state) {}
|
||||
|
||||
protected:
|
||||
virtual void ConfigChanged(OvmsConfigParam* param);
|
||||
|
@ -471,6 +483,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);
|
||||
|
@ -631,7 +649,7 @@ class OvmsVehicle : public InternalRamAllocated
|
|||
float* m_bms_vmins; // BMS minimum voltages seen (since reset)
|
||||
float* m_bms_vmaxs; // BMS maximum voltages seen (since reset)
|
||||
float* m_bms_vdevmaxs; // BMS maximum voltage deviations seen (since reset)
|
||||
short* m_bms_valerts; // BMS voltage deviation alerts (since reset)
|
||||
OvmsStatus* m_bms_valerts; // BMS voltage deviation alerts (since reset)
|
||||
int m_bms_valerts_new; // BMS new voltage alerts since last notification
|
||||
int m_bms_vstddev_cnt; // BMS internal stddev counter
|
||||
float m_bms_vstddev_avg; // BMS internal stddev average
|
||||
|
@ -640,7 +658,7 @@ class OvmsVehicle : public InternalRamAllocated
|
|||
float* m_bms_tmins; // BMS minimum temperatures seen (since reset)
|
||||
float* m_bms_tmaxs; // BMS maximum temperatures seen (since reset)
|
||||
float* m_bms_tdevmaxs; // BMS maximum temperature deviations seen (since reset)
|
||||
short* m_bms_talerts; // BMS temperature deviation alerts (since reset)
|
||||
OvmsStatus* m_bms_talerts; // BMS temperature deviation alerts (since reset)
|
||||
int m_bms_talerts_new; // BMS new temperature alerts since last notification
|
||||
bool m_bms_has_temperatures; // True if BMS has a complete set of temperature values
|
||||
std::vector<bool> m_bms_bitset_v; // BMS tracking: true if corresponding voltage set
|
||||
|
@ -686,8 +704,10 @@ 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);
|
||||
};
|
||||
|
||||
template<typename Type> OvmsVehicle* CreateVehicle()
|
||||
|
|
|
@ -60,7 +60,7 @@ void OvmsVehicle::BmsSetCellArrangementVoltage(int readings, int readingspermodu
|
|||
if (m_bms_vdevmaxs != NULL) delete m_bms_vdevmaxs;
|
||||
m_bms_vdevmaxs = new float[readings];
|
||||
if (m_bms_valerts != NULL) delete m_bms_valerts;
|
||||
m_bms_valerts = new short[readings];
|
||||
m_bms_valerts = new OvmsStatus[readings];
|
||||
m_bms_valerts_new = 0;
|
||||
|
||||
m_bms_bitset_v.clear();
|
||||
|
@ -72,6 +72,129 @@ void OvmsVehicle::BmsSetCellArrangementVoltage(int readings, int readingspermodu
|
|||
BmsResetCellVoltages(true);
|
||||
}
|
||||
|
||||
// Internal entry for changing cell arrangements.
|
||||
struct reading_entry_t
|
||||
{
|
||||
int cell_no;
|
||||
float entry;
|
||||
};
|
||||
|
||||
/**
|
||||
* Changes the cell arrangement for Voltage, if needs be restoring any readings that were there.
|
||||
* Really should only do work the first time it is called.. as for any one car, the number of readings
|
||||
* should be consistent.
|
||||
* @return true If the cell arrangement was changed.
|
||||
*/
|
||||
bool OvmsVehicle::BmsCheckChangeCellArrangementVoltage(int readings, int readingspermodule /*=0*/)
|
||||
{
|
||||
bool res = false;
|
||||
if (readingspermodule <= 0)
|
||||
{
|
||||
// Passing in 0 will leave the readings per module unchanged.
|
||||
readingspermodule = m_bms_readingspermodule_v;
|
||||
}
|
||||
if (readings != m_bms_readings_v)
|
||||
{
|
||||
res = true;
|
||||
if (m_bms_bitset_cv == 0)
|
||||
{
|
||||
BmsSetCellArrangementVoltage(readings, readingspermodule);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Store (potentially) sparse readings into a vector.
|
||||
std::vector<reading_entry_t> cells;
|
||||
// At most we will need the number of voltages set in the bitset.
|
||||
cells.reserve(m_bms_bitset_cv);
|
||||
reading_entry_t reading;
|
||||
int maxv = readings;
|
||||
if (m_bms_readings_v < maxv)
|
||||
{
|
||||
maxv = m_bms_readings_v;
|
||||
}
|
||||
for (int i = 0; i< maxv; ++i)
|
||||
{
|
||||
if (m_bms_bitset_v[i])
|
||||
{
|
||||
reading.cell_no = i;
|
||||
reading.entry = m_bms_voltages[i];
|
||||
cells.insert(cells.end(),reading);
|
||||
}
|
||||
}
|
||||
BmsSetCellArrangementVoltage(readings, readingspermodule);
|
||||
for ( std::vector<reading_entry_t>::iterator iter = cells.begin(); iter != cells.end(); ++iter)
|
||||
{
|
||||
BmsSetCellVoltage(iter->cell_no, iter->entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (readingspermodule != m_bms_readingspermodule_v)
|
||||
{
|
||||
// This only changes the read-out.
|
||||
m_bms_readingspermodule_v = readingspermodule;
|
||||
res = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the cell arrangement for Temperature, if needs be restoring any readings that were there.
|
||||
* Really should only do work the first time it is called.. as for any one car, the number of readings
|
||||
* should be consistent.
|
||||
* @return true If the cell arrangement was changed.
|
||||
*/
|
||||
bool OvmsVehicle::BmsCheckChangeCellArrangementTemperature(int readings, int readingspermodule /*=0*/)
|
||||
{
|
||||
bool res = false;
|
||||
if (readingspermodule <= 0)
|
||||
{
|
||||
// Passing in 0 will leave the readings per module unchanged.
|
||||
readingspermodule = m_bms_readingspermodule_t;
|
||||
}
|
||||
if (readings != m_bms_readings_t)
|
||||
{
|
||||
res = true;
|
||||
if (m_bms_bitset_ct == 0)
|
||||
{
|
||||
BmsSetCellArrangementTemperature(readings, readingspermodule);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Store (potentially) sparse readings into a vector.
|
||||
std::vector<reading_entry_t> cells;
|
||||
// At most we will need the number of Temperatures set in the bitset.
|
||||
cells.reserve(m_bms_bitset_ct);
|
||||
reading_entry_t reading;
|
||||
int maxv = readings;
|
||||
if (m_bms_readings_t < maxv)
|
||||
{
|
||||
maxv = m_bms_readings_t;
|
||||
}
|
||||
for (int i = 0; i< maxv; ++i)
|
||||
{
|
||||
if (m_bms_bitset_t[i])
|
||||
{
|
||||
reading.cell_no = i;
|
||||
reading.entry = m_bms_temperatures[i];
|
||||
cells.insert(cells.end(),reading);
|
||||
}
|
||||
}
|
||||
BmsSetCellArrangementTemperature(readings, readingspermodule);
|
||||
for ( std::vector<reading_entry_t>::iterator iter = cells.begin(); iter != cells.end(); ++iter)
|
||||
{
|
||||
BmsSetCellTemperature(iter->cell_no, iter->entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (readingspermodule != m_bms_readingspermodule_t)
|
||||
{
|
||||
// This only changes the read-out.
|
||||
m_bms_readingspermodule_t = readingspermodule;
|
||||
res = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void OvmsVehicle::BmsSetCellArrangementTemperature(int readings, int readingspermodule)
|
||||
{
|
||||
if (m_bms_temperatures != NULL) delete m_bms_temperatures;
|
||||
|
@ -83,7 +206,7 @@ void OvmsVehicle::BmsSetCellArrangementTemperature(int readings, int readingsper
|
|||
if (m_bms_tdevmaxs != NULL) delete m_bms_tdevmaxs;
|
||||
m_bms_tdevmaxs = new float[readings];
|
||||
if (m_bms_talerts != NULL) delete m_bms_talerts;
|
||||
m_bms_talerts = new short[readings];
|
||||
m_bms_talerts = new OvmsStatus[readings];
|
||||
m_bms_talerts_new = 0;
|
||||
|
||||
m_bms_bitset_t.clear();
|
||||
|
@ -153,7 +276,7 @@ void OvmsVehicle::BmsSetCellLimitsTemperature(float min, float max)
|
|||
|
||||
void OvmsVehicle::BmsSetCellVoltage(int index, float value)
|
||||
{
|
||||
//ESP_LOGV(TAG,"BmsSetCellVoltage(%d,%f) c=%d", index, value, m_bms_bitset_cv);
|
||||
// ESP_LOGV(TAG,"BmsSetCellVoltage(%d,%f) c=%d", index, value, m_bms_bitset_cv);
|
||||
if ((index<0)||(index>=m_bms_readings_v)) return;
|
||||
if ((value<m_bms_limit_vmin)||(value>m_bms_limit_vmax)) return;
|
||||
m_bms_voltages[index] = value;
|
||||
|
@ -245,20 +368,20 @@ void OvmsVehicle::BmsSetCellVoltage(int index, float value)
|
|||
dev = ROUNDPREC(m_bms_voltages[i] - avg, 5);
|
||||
if (ABS(dev) > ABS(m_bms_vdevmaxs[i]))
|
||||
m_bms_vdevmaxs[i] = dev;
|
||||
if (ABS(dev) >= stddev + thr_alert && m_bms_valerts[i] < 2)
|
||||
if (ABS(dev) >= stddev + thr_alert && m_bms_valerts[i] <= OvmsStatus::Warn)
|
||||
{
|
||||
m_bms_valerts[i] = 2;
|
||||
m_bms_valerts[i] = OvmsStatus::Alert;
|
||||
m_bms_valerts_new++; // trigger notification
|
||||
}
|
||||
else if (ABS(dev) >= stddev + thr_warn && m_bms_valerts[i] < 1)
|
||||
m_bms_valerts[i] = 1;
|
||||
else if (ABS(dev) >= stddev + thr_warn && m_bms_valerts[i] < OvmsStatus::Warn)
|
||||
m_bms_valerts[i] = OvmsStatus::Warn;
|
||||
}
|
||||
|
||||
// Publish deviation maximums & alerts:
|
||||
if (stddev > StandardMetrics.ms_v_bat_pack_vstddev_max->AsFloat())
|
||||
StandardMetrics.ms_v_bat_pack_vstddev_max->SetValue(stddev);
|
||||
StandardMetrics.ms_v_bat_cell_vdevmax->SetElemValues(0, m_bms_readings_v, m_bms_vdevmaxs);
|
||||
StandardMetrics.ms_v_bat_cell_valert->SetElemValues(0, m_bms_readings_v, m_bms_valerts);
|
||||
StandardMetrics.ms_v_bat_cell_valert->SetElemValues(0, m_bms_readings_v, (short *)m_bms_valerts);
|
||||
}
|
||||
|
||||
// complete:
|
||||
|
@ -275,7 +398,7 @@ void OvmsVehicle::BmsSetCellVoltage(int index, float value)
|
|||
|
||||
void OvmsVehicle::BmsSetCellTemperature(int index, float value)
|
||||
{
|
||||
//ESP_LOGV(TAG,"BmsSetCellTemperature(%d,%f) c=%d", index, value, m_bms_bitset_ct);
|
||||
// ESP_LOGV(TAG,"BmsSetCellTemperature(%d,%f) c=%d", index, value, m_bms_bitset_ct);
|
||||
if ((index<0)||(index>=m_bms_readings_t)) return;
|
||||
if ((value<m_bms_limit_tmin)||(value>m_bms_limit_tmax)) return;
|
||||
m_bms_temperatures[index] = value;
|
||||
|
@ -319,13 +442,13 @@ void OvmsVehicle::BmsSetCellTemperature(int index, float value)
|
|||
dev = ROUNDPREC(m_bms_temperatures[i] - avg, 2);
|
||||
if (ABS(dev) > ABS(m_bms_tdevmaxs[i]))
|
||||
m_bms_tdevmaxs[i] = dev;
|
||||
if (ABS(dev) >= stddev + thr_alert && m_bms_talerts[i] < 2)
|
||||
if (ABS(dev) >= stddev + thr_alert && m_bms_talerts[i] < OvmsStatus::Alert)
|
||||
{
|
||||
m_bms_talerts[i] = 2;
|
||||
m_bms_talerts[i] = OvmsStatus::Alert;
|
||||
m_bms_talerts_new++; // trigger notification
|
||||
}
|
||||
else if (ABS(dev) >= stddev + thr_warn && m_bms_valerts[i] < 1)
|
||||
m_bms_talerts[i] = 1;
|
||||
else if (ABS(dev) >= stddev + thr_warn && m_bms_valerts[i] < OvmsStatus::Warn)
|
||||
m_bms_talerts[i] = OvmsStatus::Warn;
|
||||
}
|
||||
|
||||
// publish to metrics:
|
||||
|
@ -341,7 +464,7 @@ void OvmsVehicle::BmsSetCellTemperature(int index, float value)
|
|||
StandardMetrics.ms_v_bat_cell_tmin->SetElemValues(0, m_bms_readings_t, m_bms_tmins);
|
||||
StandardMetrics.ms_v_bat_cell_tmax->SetElemValues(0, m_bms_readings_t, m_bms_tmaxs);
|
||||
StandardMetrics.ms_v_bat_cell_tdevmax->SetElemValues(0, m_bms_readings_t, m_bms_tdevmaxs);
|
||||
StandardMetrics.ms_v_bat_cell_talert->SetElemValues(0, m_bms_readings_t, m_bms_talerts);
|
||||
StandardMetrics.ms_v_bat_cell_talert->SetElemValues(0, m_bms_readings_t, (short *) m_bms_talerts);
|
||||
|
||||
// complete:
|
||||
m_bms_has_temperatures = true;
|
||||
|
@ -365,7 +488,7 @@ void OvmsVehicle::BmsRestartCellVoltages()
|
|||
void OvmsVehicle::BmsRestartCellTemperatures()
|
||||
{
|
||||
m_bms_bitset_t.clear();
|
||||
m_bms_bitset_v.resize(m_bms_readings_t);
|
||||
m_bms_bitset_t.resize(m_bms_readings_t);
|
||||
m_bms_bitset_ct = 0;
|
||||
}
|
||||
|
||||
|
@ -382,7 +505,7 @@ void OvmsVehicle::BmsResetCellVoltages(bool full /*=false*/)
|
|||
m_bms_vmins[k] = 0;
|
||||
m_bms_vmaxs[k] = 0;
|
||||
m_bms_vdevmaxs[k] = 0;
|
||||
m_bms_valerts[k] = 0;
|
||||
m_bms_valerts[k] = OvmsStatus::OK;
|
||||
}
|
||||
m_bms_valerts_new = 0;
|
||||
m_bms_vstddev_cnt = 0;
|
||||
|
@ -409,7 +532,7 @@ void OvmsVehicle::BmsResetCellTemperatures(bool full /*=false*/)
|
|||
m_bms_tmins[k] = 0;
|
||||
m_bms_tmaxs[k] = 0;
|
||||
m_bms_tdevmaxs[k] = 0;
|
||||
m_bms_talerts[k] = 0;
|
||||
m_bms_talerts[k] = OvmsStatus::OK;
|
||||
}
|
||||
m_bms_talerts_new = 0;
|
||||
if (full) StandardMetrics.ms_v_bat_cell_temp->ClearValue();
|
||||
|
@ -427,81 +550,217 @@ void OvmsVehicle::BmsResetCellStats()
|
|||
BmsResetCellTemperatures(false);
|
||||
}
|
||||
|
||||
void OvmsVehicle::BmsStatus(int verbosity, OvmsWriter* writer)
|
||||
template<typename INT>
|
||||
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;
|
||||
}
|
||||
metric_unit_t user_temp = UnitNotFound;
|
||||
std::string temp_unit;
|
||||
if (show_temperature)
|
||||
{
|
||||
user_temp = OvmsMetricGetUserUnit(GrpTemp, Celcius);
|
||||
// (To Check: '°' is not SMS safe, so we only output 'C')
|
||||
temp_unit = OvmsMetricUnitLabel(user_temp);
|
||||
}
|
||||
|
||||
int vwarn=0, valert=0;
|
||||
int twarn=0, talert=0;
|
||||
for (c=0; c<m_bms_readings_v; c++) {
|
||||
if (m_bms_valerts[c]==1) vwarn++;
|
||||
if (m_bms_valerts[c]==2) valert++;
|
||||
}
|
||||
for (c=0; c<m_bms_readings_t; c++) {
|
||||
if (m_bms_talerts[c]==1) twarn++;
|
||||
if (m_bms_talerts[c]==2) talert++;
|
||||
}
|
||||
for (c=0; c<m_bms_readings_v; c++)
|
||||
{
|
||||
switch (m_bms_valerts[c])
|
||||
{
|
||||
case OvmsStatus::OK: break;
|
||||
case OvmsStatus::Warn: vwarn++; break;
|
||||
case OvmsStatus::Alert: valert++;break;
|
||||
}
|
||||
}
|
||||
for (c=0; c<m_bms_readings_t; c++)
|
||||
{
|
||||
switch (m_bms_talerts[c])
|
||||
{
|
||||
case OvmsStatus::OK: break;
|
||||
case OvmsStatus::Warn: twarn++; break;
|
||||
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.1f%s [%5.1f%s - %5.1f%s]\n",
|
||||
StdMetrics.ms_v_bat_pack_tavg->AsFloat(0, user_temp), temp_unit.c_str(),
|
||||
StdMetrics.ms_v_bat_pack_tmin->AsFloat(0, user_temp), temp_unit.c_str(),
|
||||
StdMetrics.ms_v_bat_pack_tmax->AsFloat(0, user_temp), temp_unit.c_str());
|
||||
writer->printf(" Deviation: SD %6.2f%s [max %.2f%s], %d warnings, %d alerts\n",
|
||||
StdMetrics.ms_v_bat_pack_tstddev->AsFloat(0, user_temp), temp_unit.c_str(),
|
||||
StdMetrics.ms_v_bat_pack_tstddev_max->AsFloat(0, user_temp), temp_unit.c_str(),
|
||||
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;c<m_bms_readingspermodule_v;c++) { writer->printf("-------"); }
|
||||
writer->printf("-+");
|
||||
for (c=0;c<m_bms_readingspermodule_t;c++) { writer->printf("-------"); }
|
||||
writer->puts("-+");
|
||||
writer->printf("%3d |",module+1);
|
||||
for (c=0; c<m_bms_readingspermodule_v; c++)
|
||||
if (show_voltage)
|
||||
{
|
||||
if (kv < m_bms_readings_v)
|
||||
writer->printf(" %5.3fV",m_bms_voltages[kv++]);
|
||||
else
|
||||
writer->printf(" ");
|
||||
for (c=0;c<max_cols_v;c++) { writer->printf("-------"); }
|
||||
writer->printf("-+");
|
||||
}
|
||||
writer->printf(" |");
|
||||
for (c=0; c<m_bms_readingspermodule_t; c++)
|
||||
|
||||
if (show_temperature) {
|
||||
for (c=0;c<max_cols_t;c++) { writer->printf("-------"); }
|
||||
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<max_cols_v; c++)
|
||||
{
|
||||
if (kv < m_bms_readings_v && (reading_left_v > 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<m_bms_readingspermodule_t; c++)
|
||||
{
|
||||
if (kt < m_bms_readings_t && (reading_left_t > 0))
|
||||
{
|
||||
writer->printf(" %5.1f%s",UnitConvert(Celcius, user_temp, m_bms_temperatures[kt]), temp_unit.c_str());
|
||||
--reading_left_t;
|
||||
++kt;
|
||||
}
|
||||
else
|
||||
writer->printf(" ");
|
||||
}
|
||||
writer->printf(" |");
|
||||
}
|
||||
writer->puts("");
|
||||
}
|
||||
writer->puts(" |");
|
||||
}
|
||||
|
||||
writer->printf(" +");
|
||||
for (c=0;c<m_bms_readingspermodule_v;c++) { writer->printf("-------"); }
|
||||
writer->printf("-+");
|
||||
for (c=0;c<m_bms_readingspermodule_t;c++) { writer->printf("-------"); }
|
||||
writer->puts("-+");
|
||||
if (show_voltage)
|
||||
{
|
||||
for (c=0;c<max_cols_v;c++) { writer->printf("-------"); }
|
||||
writer->printf("-+");
|
||||
}
|
||||
if (show_temperature)
|
||||
{
|
||||
for (c=0;c<max_cols_t;c++) { writer->printf("-------"); }
|
||||
writer->printf("-+");
|
||||
}
|
||||
writer->puts("");
|
||||
}
|
||||
|
||||
bool OvmsVehicle::FormatBmsAlerts(int verbosity, OvmsWriter* writer, bool show_warnings)
|
||||
|
@ -515,14 +774,18 @@ bool OvmsVehicle::FormatBmsAlerts(int verbosity, OvmsWriter* writer, bool show_w
|
|||
writer->printf("Voltage: StdDev %dmV", (int)(StdMetrics.ms_v_bat_pack_vstddev_max->AsFloat() * 1000));
|
||||
for (int i=0; i<m_bms_readings_v; i++)
|
||||
{
|
||||
int sts = StdMetrics.ms_v_bat_cell_valert->GetElemValue(i);
|
||||
if (sts == 0) continue;
|
||||
if (sts == 1 && !show_warnings) continue;
|
||||
OvmsStatus sts = OvmsStatus(StdMetrics.ms_v_bat_cell_valert->GetElemValue(i));
|
||||
switch (sts)
|
||||
{
|
||||
case OvmsStatus::OK: continue;
|
||||
case OvmsStatus::Warn: if (!show_warnings) continue;
|
||||
case OvmsStatus::Alert: ;
|
||||
}
|
||||
has_valerts++;
|
||||
if (verbose || has_valerts <= 5)
|
||||
{
|
||||
int dev = StdMetrics.ms_v_bat_cell_vdevmax->GetElemValue(i) * 1000;
|
||||
writer->printf("\n %c #%02d: %+4dmV", (sts==1) ? '?' : '!', i+1, dev);
|
||||
writer->printf("\n %c #%02d: %+4dmV", (sts==OvmsStatus::Warn) ? '?' : '!', i+1, dev);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -533,18 +796,23 @@ bool OvmsVehicle::FormatBmsAlerts(int verbosity, OvmsWriter* writer, bool show_w
|
|||
writer->printf("%s\n", has_valerts ? "" : ", cells OK");
|
||||
|
||||
// Temperatures:
|
||||
// (Note: '°' is not SMS safe, so we only output 'C')
|
||||
writer->printf("Temperature: StdDev %.1fC", StdMetrics.ms_v_bat_pack_tstddev_max->AsFloat());
|
||||
metric_unit_t user_temp = OvmsMetricGetUserUnit(GrpTemp, Celcius);
|
||||
std::string temp_unit = OvmsMetricUnitLabel(user_temp);
|
||||
writer->printf("Temperature: StdDev %.1f%s", StdMetrics.ms_v_bat_pack_tstddev_max->AsFloat(0, user_temp), temp_unit.c_str());
|
||||
for (int i=0; i<m_bms_readings_v; i++)
|
||||
{
|
||||
int sts = StdMetrics.ms_v_bat_cell_talert->GetElemValue(i);
|
||||
if (sts == 0) continue;
|
||||
if (sts == 1 && !show_warnings) continue;
|
||||
OvmsStatus sts = OvmsStatus(StdMetrics.ms_v_bat_cell_talert->GetElemValue(i));
|
||||
switch (sts)
|
||||
{
|
||||
case OvmsStatus::OK: continue;
|
||||
case OvmsStatus::Warn: if (!show_warnings) continue;
|
||||
case OvmsStatus::Alert: ;
|
||||
}
|
||||
has_talerts++;
|
||||
if (verbose || has_talerts <= 5)
|
||||
{
|
||||
float dev = StdMetrics.ms_v_bat_cell_tdevmax->GetElemValue(i);
|
||||
writer->printf("\n %c #%02d: %+3.1fC", (sts==1) ? '?' : '!', i+1, dev);
|
||||
float dev = StdMetrics.ms_v_bat_cell_tdevmax->GetElemValue(i, user_temp);
|
||||
writer->printf("\n %c #%02d: %+3.1f%s", (sts==OvmsStatus::Warn) ? '?' : '!', i+1, dev, temp_unit.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
=======================
|
||||
Renault Zoe
|
||||
=======================
|
||||
|
||||
Vehicle Type: **RZ2**
|
||||
|
||||
This vehicle type supports the Renault Zoe(PH2)
|
||||
|
||||
----------------
|
||||
Support Overview
|
||||
----------------
|
||||
|
||||
=========================== ==============
|
||||
Function Support Status
|
||||
=========================== ==============
|
||||
Hardware OVMS v3 (or later)
|
||||
Vehicle Cable OBD-II to DB9 Data Cable for OVMS (1441200 right, or 1139300 left)
|
||||
GSM Antenna 1000500 Open Vehicles OVMS GSM Antenna (or any compatible antenna)
|
||||
GPS Antenna 1020200 Universal GPS Antenna (SMA Connector) (or any compatible antenna)
|
||||
SOC Display Yes
|
||||
Range Display Yes
|
||||
GPS Location Yes (from modem module GPS)
|
||||
Speed Display Yes
|
||||
Temperature Display Yes (External Temp and Battery)
|
||||
BMS v+t Display Yes
|
||||
TPMS Display Zoe No
|
||||
TPMS Display Kangoo No
|
||||
Charge Status Display Yes
|
||||
Charge Interruption Alerts No
|
||||
Charge Control No
|
||||
Cabin Pre-heat/cool Control No
|
||||
Lock/Unlock Vehicle No
|
||||
Valet Mode Control No
|
||||
Others
|
||||
=========================== ==============
|
|
@ -7,7 +7,7 @@
|
|||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
||||
|
||||
ifdef CONFIG_OVMS_VEHICLE_RENAULTZOE_PH2
|
||||
ifdef CONFIG_OVMS_VEHICLE_RENAULTZOE_PH2_CAN
|
||||
COMPONENT_ADD_INCLUDEDIRS:=src
|
||||
COMPONENT_SRCDIRS:=src
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
49
OVMS.V3/components/vehicle_renaultzoe_ph2_can/docs/index.rst
Normal file
49
OVMS.V3/components/vehicle_renaultzoe_ph2_can/docs/index.rst
Normal file
|
@ -0,0 +1,49 @@
|
|||
=======================================
|
||||
Renault Zoe Phase 2 (CAN direct access)
|
||||
=======================================
|
||||
|
||||
Vehicle Type: **RZ2C**
|
||||
|
||||
This vehicle type supports the Renault Zoe(PH2) through direct CAN connection.
|
||||
You connect CAN1 interface of the OVMS module to M-CAN bus on your Zoe, you can intercept it at TCU, Radio (IVI) or Can Core Gateway behind glovebox.
|
||||
|
||||
----------------
|
||||
Support Overview
|
||||
----------------
|
||||
|
||||
=========================== ==============
|
||||
Function Support Status
|
||||
=========================== ==============
|
||||
Hardware OVMS v3.3
|
||||
Vehicle Cable DIY cable to intercept M-CAN on TCU, Radio/IVI or Can Core Gateway
|
||||
GSM Antenna SMA to Fakra adapter, if you use Zoes antennas (disconnect TCU)
|
||||
GPS Antenna SMA to Fakra adapter, if you use Zoes antennas (disconnect TCU)
|
||||
SOC Display Yes
|
||||
Range Display Yes
|
||||
GPS Location Yes (from modem module GPS)
|
||||
Speed Display Yes
|
||||
Temperature Display Yes (Battery, Outside, Cabin, Motor, Inverter, Tyres)
|
||||
BMS v+t Display Yes
|
||||
TPMS Display Zoe Yes (Pressure and temperature)
|
||||
Charge Status Display Yes
|
||||
Charge Interruption Alerts Yes
|
||||
Charge Control No
|
||||
Cabin Pre-heat/cool Control No
|
||||
Lock/Unlock Vehicle No
|
||||
Valet Mode Control No
|
||||
=========================== ==============
|
||||
|
||||
Others:
|
||||
|
||||
=================================== ==============
|
||||
Door open/close Yes (exclude hood)
|
||||
Battery full charge cycles Yes
|
||||
Battery max charge, recd pwr Yes
|
||||
Trip counter from Car No
|
||||
Battery lifetime gauges Yes (Charged, Recd and Used kWh)
|
||||
Heat pump power, rpm and hp press. Yes
|
||||
Aux power gauges Yes (testing needed)
|
||||
Charge type Yes (DC charge, testing needed)
|
||||
Headlights Status Yes (lowbeam)
|
||||
Charge efficiency calculation Yes (but only for AC, pf is measured with power analyzer and included as statics)
|
||||
=================================== ==============
|
224
OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/BCM_pids.cpp
Normal file
224
OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/BCM_pids.cpp
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Date: 19th Nov 2022
|
||||
;
|
||||
; (C) 2022 Carsten Schmiemann
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
#include "vehicle_renaultzoe_ph2_can.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::IncomingBCM(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x6300: { // TPMS pressure - front left
|
||||
if ((CAN_UINT(0) * 7.5) < 7672) {
|
||||
StandardMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_FL, (float)CAN_UINT(0) * 7.5 / 10, kPa);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6300 BCM tpms pressure FL: %f", CAN_UINT(0) * 7.5);
|
||||
break;
|
||||
}
|
||||
case 0x6301: { // TPMS pressure - front right
|
||||
if ((CAN_UINT(0) * 7.5) < 7672) {
|
||||
StandardMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_FR, (float)CAN_UINT(0) * 7.5 / 10, kPa);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6301 BCM tpms pressure FR: %f", CAN_UINT(0) * 7.5);
|
||||
break;
|
||||
}
|
||||
case 0x6302: { // TPMS pressure - rear left
|
||||
if ((CAN_UINT(0) * 7.5) < 7672) {
|
||||
StandardMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_RL, (float)CAN_UINT(0) * 7.5 / 10, kPa);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6302 BCM tpms pressure RL: %f", CAN_UINT(0) * 7.5);
|
||||
break;
|
||||
}
|
||||
case 0x6303: { // TPMS pressure - rear right
|
||||
if ((CAN_UINT(0) * 7.5) < 7672) {
|
||||
StandardMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_RR, (float)CAN_UINT(0) * 7.5 / 10, kPa);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6303 BCM tpms pressure RR: %f", CAN_UINT(0) * 7.5);
|
||||
break;
|
||||
}
|
||||
case 0x6310: { // TPMS temp - front left
|
||||
if (CAN_BYTE(0) < 127) {
|
||||
StandardMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_FL, CAN_BYTE(0) - 30, Celcius);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6310 BCM tpms temp FL: %d", CAN_NIB(0));
|
||||
break;
|
||||
}
|
||||
case 0x6311: { // TPMS temp - front right
|
||||
if (CAN_BYTE(0) < 127) {
|
||||
StandardMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_FR, CAN_BYTE(0) - 30, Celcius);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6311 BCM tpms temp FR: %d", CAN_NIBL(0));
|
||||
break;
|
||||
}
|
||||
case 0x6312: { // TPMS temp - rear left
|
||||
if (CAN_BYTE(0) < 127) {
|
||||
StandardMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_RL, CAN_BYTE(0) - 30, Celcius);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6312 BCM tpms temp RL: %d", CAN_NIBH(0));
|
||||
break;
|
||||
}
|
||||
case 0x6313: { // TPMS temp - rear right
|
||||
if (CAN_BYTE(0) < 127) {
|
||||
StandardMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_RR, CAN_BYTE(0) - 30, Celcius);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6313 BCM tpms temp RR: %d", CAN_BYTE(0));
|
||||
break;
|
||||
}
|
||||
case 0x4109: { // TPMS alert - front left
|
||||
if (CAN_UINT(0) == 0) {
|
||||
StandardMetrics.ms_v_tpms_alert->SetElemValue(MS_V_TPMS_IDX_FL, 0);
|
||||
}
|
||||
if (CAN_UINT(0) == 1 || CAN_UINT(0) == 3 || CAN_UINT(0) == 5 || CAN_UINT(0) == 7) {
|
||||
StandardMetrics.ms_v_tpms_alert->SetElemValue(MS_V_TPMS_IDX_FL, 2);
|
||||
}
|
||||
if (CAN_UINT(0) == 2 || CAN_UINT(0) == 4 || CAN_UINT(0) == 6 ) {
|
||||
StandardMetrics.ms_v_tpms_alert->SetElemValue(MS_V_TPMS_IDX_FL, 1);
|
||||
}
|
||||
//ESP_LOGD(TAG, "40FF BCM tpms alert FL: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x410A: { // TPMS alert - front right
|
||||
if (CAN_UINT(0) == 0) {
|
||||
StandardMetrics.ms_v_tpms_alert->SetElemValue(MS_V_TPMS_IDX_FR, 0);
|
||||
}
|
||||
if (CAN_UINT(0) == 1 || CAN_UINT(0) == 3 || CAN_UINT(0) == 5 || CAN_UINT(0) == 7) {
|
||||
StandardMetrics.ms_v_tpms_alert->SetElemValue(MS_V_TPMS_IDX_FR, 2);
|
||||
}
|
||||
if (CAN_UINT(0) == 2 || CAN_UINT(0) == 4 || CAN_UINT(0) == 6 ) {
|
||||
StandardMetrics.ms_v_tpms_alert->SetElemValue(MS_V_TPMS_IDX_FR, 1);
|
||||
}
|
||||
//ESP_LOGD(TAG, "40FF BCM tpms alert FR: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x410B: { // TPMS alert - rear left
|
||||
if (CAN_UINT(0) == 0) {
|
||||
StandardMetrics.ms_v_tpms_alert->SetElemValue(MS_V_TPMS_IDX_RL, 0);
|
||||
}
|
||||
if (CAN_UINT(0) == 1 || CAN_UINT(0) == 3 || CAN_UINT(0) == 5 || CAN_UINT(0) == 7) {
|
||||
StandardMetrics.ms_v_tpms_alert->SetElemValue(MS_V_TPMS_IDX_RL, 2);
|
||||
}
|
||||
if (CAN_UINT(0) == 2 || CAN_UINT(0) == 4 || CAN_UINT(0) == 6 ) {
|
||||
StandardMetrics.ms_v_tpms_alert->SetElemValue(MS_V_TPMS_IDX_RL, 1);
|
||||
}
|
||||
//ESP_LOGD(TAG, "40FF BCM tpms alert RL: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x410C: { // TPMS alert - rear right
|
||||
if (CAN_UINT(0) == 0) {
|
||||
StandardMetrics.ms_v_tpms_alert->SetElemValue(MS_V_TPMS_IDX_RR, 0);
|
||||
}
|
||||
if (CAN_UINT(0) == 1 || CAN_UINT(0) == 3 || CAN_UINT(0) == 5 || CAN_UINT(0) == 7) {
|
||||
StandardMetrics.ms_v_tpms_alert->SetElemValue(MS_V_TPMS_IDX_RR, 2);
|
||||
}
|
||||
if (CAN_UINT(0) == 2 || CAN_UINT(0) == 4 || CAN_UINT(0) == 6 ) {
|
||||
StandardMetrics.ms_v_tpms_alert->SetElemValue(MS_V_TPMS_IDX_RR, 1);
|
||||
}
|
||||
//ESP_LOGD(TAG, "40FF BCM tpms alert RR: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x8004: { //Car secure aka vehicle locked
|
||||
StandardMetrics.ms_v_env_locked->SetValue((bool)CAN_UINT(0));
|
||||
//ESP_LOGD(TAG, "8004 BCM Car Secure S: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x6026: { //Front left door
|
||||
StandardMetrics.ms_v_door_fl->SetValue((bool)CAN_UINT(0));
|
||||
//ESP_LOGD(TAG, "6026 BCM Front left door: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x6027: { //Front right door
|
||||
StandardMetrics.ms_v_door_fr->SetValue((bool)CAN_UINT(0));
|
||||
//ESP_LOGD(TAG, "6027 BCM Front right door: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x61B2: { //Rear left door
|
||||
StandardMetrics.ms_v_door_rl->SetValue((bool)CAN_UINT(0));
|
||||
//ESP_LOGD(TAG, "61B2 BCM Rear left door: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x61B3: { //Rear right door
|
||||
StandardMetrics.ms_v_door_rr->SetValue((bool)CAN_UINT(0));
|
||||
//ESP_LOGD(TAG, "61B3 Rear right door: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x609B: { //Tailgate
|
||||
StandardMetrics.ms_v_door_trunk->SetValue((bool)CAN_UINT(0));
|
||||
//ESP_LOGD(TAG, "609B Tailgate: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x4186: { //Low beam lights
|
||||
StandardMetrics.ms_v_env_headlights->SetValue((bool)CAN_UINT(0));
|
||||
/*if ((bool)CAN_UINT(0)) {
|
||||
ESP_LOGD(TAG, "4186 Low beam lights: active");
|
||||
} else {
|
||||
ESP_LOGD(TAG, "4186 Low beam lights: inactive");
|
||||
}*/
|
||||
break;
|
||||
}
|
||||
case 0x60C6: { //Ignition relay (switch)
|
||||
/*if ((bool)CAN_UINT(0)) {
|
||||
ESP_LOGD(TAG, "60C6 Ignition relay: active");
|
||||
} else {
|
||||
ESP_LOGD(TAG, "60C6 Ignition relay: inactive");
|
||||
}*/
|
||||
if (!CarIsCharging) { //Igniton while charging
|
||||
StandardMetrics.ms_v_env_on->SetValue((bool)CAN_UINT(0));
|
||||
StandardMetrics.ms_v_env_awake->SetValue((bool)CAN_UINT(0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x4060: { //Vehicle identificaftion number
|
||||
zoe_vin[0] = CAN_BYTE(0);
|
||||
zoe_vin[1] = CAN_BYTE(1);
|
||||
zoe_vin[2] = CAN_BYTE(2);
|
||||
zoe_vin[3] = CAN_BYTE(3);
|
||||
zoe_vin[4] = CAN_BYTE(4);
|
||||
zoe_vin[5] = CAN_BYTE(5);
|
||||
zoe_vin[6] = CAN_BYTE(6);
|
||||
zoe_vin[7] = CAN_BYTE(7);
|
||||
zoe_vin[8] = CAN_BYTE(8);
|
||||
zoe_vin[9] = CAN_BYTE(9);
|
||||
zoe_vin[10] = CAN_BYTE(10);
|
||||
zoe_vin[11] = CAN_BYTE(11);
|
||||
zoe_vin[12] = CAN_BYTE(12);
|
||||
zoe_vin[13] = CAN_BYTE(13);
|
||||
zoe_vin[14] = CAN_BYTE(14);
|
||||
zoe_vin[15] = CAN_BYTE(15);
|
||||
zoe_vin[16] = CAN_BYTE(16);
|
||||
zoe_vin[17] = 0;
|
||||
StandardMetrics.ms_v_vin->SetValue((string) zoe_vin);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
char *buf = NULL;
|
||||
size_t rlen = len, offset = 0;
|
||||
do {
|
||||
rlen = FormatHexDump(&buf, data + offset, rlen, 16);
|
||||
offset += 16;
|
||||
ESP_LOGW(TAG, "OBD2: unhandled reply from BCM [%02x %02x]: %s", type, pid, buf ? buf : "-");
|
||||
} while (rlen);
|
||||
if (buf)
|
||||
free(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
261
OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/EVC_pids.cpp
Normal file
261
OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/EVC_pids.cpp
Normal file
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Date: 19th Nov 2022
|
||||
;
|
||||
; (C) 2022 Carsten Schmiemann
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
#include "vehicle_renaultzoe_ph2_can.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::IncomingEVC(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x2006: { //Odometer (Total Vehicle Distance)
|
||||
StandardMetrics.ms_v_pos_odometer->SetValue((float) CAN_UINT24(0), Kilometers);
|
||||
//ESP_LOGD(TAG, "2006 EVC ms_v_pos_odometer: %d", CAN_UINT24(0));
|
||||
break;
|
||||
}
|
||||
case 0x2003: { //Vehicle Speed
|
||||
StandardMetrics.ms_v_pos_speed->SetValue((float) (CAN_UINT(0) * 0.01), KphPS);
|
||||
//ESP_LOGD(TAG, "2003 EVC ms_v_pos_speed: %f", CAN_UINT(0) * 0.01);
|
||||
break;
|
||||
}
|
||||
case 0x2005: { //12V Battery Voltage
|
||||
StandardMetrics.ms_v_charge_12v_voltage->SetValue((float) (CAN_UINT(0) * 0.01), Volts);
|
||||
//ESP_LOGD(TAG, "2005 EVC ms_v_charge_12v_voltage: %f", CAN_UINT(0) * 0.01);
|
||||
break;
|
||||
}
|
||||
case 0x21CF: { //Inverter status
|
||||
//ESP_LOGD(TAG, "21CF EVC mt_inv_status: %d", CAN_NIBL(0));
|
||||
if (CAN_NIBL(0) == 1) {
|
||||
mt_inv_status->SetValue("Inverter off");
|
||||
|
||||
} else if (CAN_NIBL(0) == 2) {
|
||||
mt_inv_status->SetValue("Inverter on");
|
||||
StandardMetrics.ms_v_door_chargeport->SetValue(false);
|
||||
} else if (CAN_NIBL(0) == 3) {
|
||||
mt_inv_status->SetValue("Inverter decharging");
|
||||
} else if (CAN_NIBL(0) == 4) {
|
||||
mt_inv_status->SetValue("Inverter alternator mode");
|
||||
} else if (CAN_NIBL(0) == 5) {
|
||||
mt_inv_status->SetValue("Inverter ready to sleep");
|
||||
} else {
|
||||
mt_inv_status->SetValue("Inverter state unknown");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x2218: { // Ambient temperature
|
||||
StandardMetrics.ms_v_env_temp->SetValue((float) (CAN_UINT(0) * 0.1 - 273), Celcius);
|
||||
//ESP_LOGD(TAG, "2218 EVC ms_v_env_temp: %f", (CAN_UINT(0) * 0.1 - 273));
|
||||
break;
|
||||
}
|
||||
case 0x2A09: { // Power consumption by consumer
|
||||
mt_bat_aux_power_consumer->SetValue((float) CAN_UINT(0) * 10, Watts);
|
||||
//ESP_LOGD(TAG, "2A09 EVC mt_bat_aux_power_consumer: %d", CAN_UINT(0) * 10);
|
||||
break;
|
||||
}
|
||||
case 0x2191: { // Power consumption by ptc
|
||||
mt_bat_aux_power_ptc->SetValue((float) CAN_UINT(0) * 10, Watts);
|
||||
//ESP_LOGD(TAG, "2191 EVC mt_bat_aux_power_ptc: %d", CAN_UINT(0) * 10);
|
||||
break;
|
||||
}
|
||||
case 0x2B85: { // Charge plug preset
|
||||
//ESP_LOGD(TAG, "2B85 EVC Charge plug present: %d", CAN_NIBL(0));
|
||||
if (CAN_NIBL(0) == 1) {
|
||||
StandardMetrics.ms_v_charge_pilot->SetValue(true);
|
||||
if (!CarPluggedIn) {
|
||||
ESP_LOGI(TAG, "Charge cable plugged in");
|
||||
CarPluggedIn = true;
|
||||
}
|
||||
}
|
||||
if (CAN_NIBL(0) == 0) {
|
||||
StandardMetrics.ms_v_charge_pilot->SetValue(false);
|
||||
if (CarPluggedIn) {
|
||||
ESP_LOGI(TAG, "Charge cable plugged out");
|
||||
CarPluggedIn = false;
|
||||
StandardMetrics.ms_v_door_chargeport->SetValue(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x2B6D: { // Charge MMI States, will be polled every 30s even car is off, because free frames are unreliable
|
||||
//ESP_LOGD(TAG, "2B6D Charge MMI States RAW: %d", CAN_NIBL(0));
|
||||
if (CAN_NIBL(0) == 0) {
|
||||
StandardMetrics.ms_v_charge_state->SetValue("stopped");
|
||||
StandardMetrics.ms_v_charge_substate->SetValue("stopped");
|
||||
StandardMetrics.ms_v_charge_inprogress->SetValue(false);
|
||||
//ESP_LOGD(TAG, "2B6D Charge MMI States : No Charge");
|
||||
}
|
||||
if (CAN_NIBL(0) == 1) {
|
||||
StandardMetrics.ms_v_charge_state->SetValue("timerwait");
|
||||
StandardMetrics.ms_v_charge_substate->SetValue("timerwait");
|
||||
//ESP_LOGD(TAG, "2B6D Charge MMI States : Waiting for a planned charge");
|
||||
}
|
||||
if (CAN_NIBL(0) == 2) {
|
||||
StandardMetrics.ms_v_charge_state->SetValue("done");
|
||||
StandardMetrics.ms_v_charge_substate->SetValue("stopped");
|
||||
StandardMetrics.ms_v_charge_inprogress->SetValue(false);
|
||||
//ESP_LOGD(TAG, "2B6D Charge MMI States : Ended charge");
|
||||
}
|
||||
if (CAN_NIBL(0) == 3) {
|
||||
StandardMetrics.ms_v_charge_state->SetValue("charging");
|
||||
StandardMetrics.ms_v_charge_substate->SetValue("onrequest");
|
||||
StandardMetrics.ms_v_charge_inprogress->SetValue(true);
|
||||
//ESP_LOGD(TAG, "2B6D Charge MMI States : Charge in progress");
|
||||
}
|
||||
if (CAN_NIBL(0) == 4) {
|
||||
StandardMetrics.ms_v_charge_state->SetValue("stopped");
|
||||
StandardMetrics.ms_v_charge_substate->SetValue("interrupted");
|
||||
StandardMetrics.ms_v_charge_inprogress->SetValue(false);
|
||||
//ESP_LOGD(TAG, "2B6D Charge MMI States : Charge failure");
|
||||
}
|
||||
if (CAN_NIBL(0) == 5) {
|
||||
StandardMetrics.ms_v_charge_state->SetValue("stopped");
|
||||
StandardMetrics.ms_v_charge_substate->SetValue("powerwait");
|
||||
StandardMetrics.ms_v_charge_inprogress->SetValue(false);
|
||||
//ESP_LOGD(TAG, "2B6D Charge MMI States : Waiting for current charge");
|
||||
}
|
||||
if (CAN_NIBL(0) == 6) {
|
||||
StandardMetrics.ms_v_door_chargeport->SetValue(true);
|
||||
//ESP_LOGD(TAG, "2B6D Charge MMI States : Chargeport opened");
|
||||
ESP_LOGI(TAG, "Chargedoor opened");
|
||||
}
|
||||
if (CAN_NIBL(0) == 8) {
|
||||
StandardMetrics.ms_v_charge_state->SetValue("prepare");
|
||||
StandardMetrics.ms_v_charge_substate->SetValue("powerwait");
|
||||
StandardMetrics.ms_v_charge_inprogress->SetValue(false);
|
||||
//ESP_LOGD(TAG, "2B6D Charge MMI States : Charge preparation");
|
||||
}
|
||||
if (!mt_bus_awake->AsBool()) {
|
||||
ZoeWakeUp();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x2B7A: { // Charge type
|
||||
//ESP_LOGD(TAG, "2B7A EVC Charge type: %d", (CAN_NIBL(0)));
|
||||
if (CAN_NIBL(0) == 0) {
|
||||
StandardMetrics.ms_v_charge_type->SetValue("undefined");
|
||||
}
|
||||
if (CAN_NIBL(0) == 1 || CAN_NIBL(0) == 2) {
|
||||
StandardMetrics.ms_v_charge_type->SetValue("type2");
|
||||
StandardMetrics.ms_v_charge_mode->SetValue("standard");
|
||||
}
|
||||
if (CAN_NIBL(0) == 3) {
|
||||
StandardMetrics.ms_v_charge_type->SetValue("chademo");
|
||||
StandardMetrics.ms_v_charge_mode->SetValue("performance");
|
||||
}
|
||||
if (CAN_NIBL(0) == 4) {
|
||||
StandardMetrics.ms_v_charge_type->SetValue("ccs");
|
||||
StandardMetrics.ms_v_charge_mode->SetValue("performance");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x3064: { // Motor rpm
|
||||
StandardMetrics.ms_v_mot_rpm->SetValue((float) (CAN_UINT(0)));
|
||||
//ESP_LOGD(TAG, "3064 EVC ms_v_mot_rpm: %d", (CAN_UINT(0)));
|
||||
break;
|
||||
}
|
||||
case 0x300F: { // AC charging power available
|
||||
mt_main_power_available->SetValue((float) (CAN_UINT(0) * 0.025), kW);
|
||||
//ESP_LOGD(TAG, "300F EVC mt_main_power_available: %f", (CAN_UINT(0) * 0.025));
|
||||
break;
|
||||
}
|
||||
case 0x300D: { // AC input current
|
||||
StandardMetrics.ms_v_charge_current->SetValue((float) (CAN_UINT(0) * 0.1), Amps);
|
||||
//Power factor measured with a Janitza UMG512 Class A power analyser to get more precision
|
||||
//Only three phases measurement at the moment
|
||||
if (StandardMetrics.ms_v_charge_current->AsFloat() > 19.0f) {
|
||||
ACInputPowerFactor = 1.0;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() > 18.0f) {
|
||||
ACInputPowerFactor = 0.997;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() > 17.0f) {
|
||||
ACInputPowerFactor = 0.99;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() > 16.0f) {
|
||||
ACInputPowerFactor = 0.978;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() > 15.0f) {
|
||||
ACInputPowerFactor = 0.948;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() > 14.0f) {
|
||||
ACInputPowerFactor = 0.931;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() > 13.0f) {
|
||||
ACInputPowerFactor = 0.916;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() > 12.0f) {
|
||||
ACInputPowerFactor = 0.902;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() > 11.0f) {
|
||||
ACInputPowerFactor = 0.888;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() > 10.0f) {
|
||||
ACInputPowerFactor = 0.905;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() > 9.0f) {
|
||||
ACInputPowerFactor = 0.929;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() > 8.0f) {
|
||||
ACInputPowerFactor = 0.901;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() > 7.0f) {
|
||||
ACInputPowerFactor = 0.775;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() < 6.0f && StandardMetrics.ms_v_charge_inprogress->AsBool(false)) {
|
||||
ACInputPowerFactor = 0.05;
|
||||
}
|
||||
if (StandardMetrics.ms_v_charge_type->AsString() == "type2" && mt_main_phases_num->AsFloat() == 3 && StandardMetrics.ms_v_charge_inprogress->AsBool(false)) {
|
||||
StandardMetrics.ms_v_charge_power->SetValue((StandardMetrics.ms_v_charge_current->AsFloat() * StandardMetrics.ms_v_charge_voltage->AsFloat() * ACInputPowerFactor * 1.732f) * 0.001, kW);
|
||||
} else if (StandardMetrics.ms_v_charge_type->AsString() == "type2" && (mt_main_phases_num->AsFloat() == 2 || mt_main_phases_num->AsFloat() == 1)) {
|
||||
StandardMetrics.ms_v_charge_power->SetValue((StandardMetrics.ms_v_charge_current->AsFloat() * StandardMetrics.ms_v_charge_voltage->AsFloat() * ACInputPowerFactor) * 0.001, kW);
|
||||
} else if (StandardMetrics.ms_v_charge_type->AsString() == "type2") {
|
||||
StandardMetrics.ms_v_charge_power->SetValue(0);
|
||||
}
|
||||
//ESP_LOGD(TAG, "300D EVC mt_main_current: %f", (CAN_UINT(0) * 0.1));
|
||||
break;
|
||||
}
|
||||
case 0x300B: { // AC phases used
|
||||
//ESP_LOGD(TAG, "300B EVC mt_main_phases: %d", (CAN_NIBL(0)));
|
||||
if (CAN_NIBL(0) == 0) {
|
||||
mt_main_phases->SetValue("one phase");
|
||||
mt_main_phases_num->SetValue(1);
|
||||
}
|
||||
if (CAN_NIBL(0) == 1) {
|
||||
mt_main_phases->SetValue("two phase");
|
||||
mt_main_phases_num->SetValue(2);
|
||||
}
|
||||
if (CAN_NIBL(0) == 2) {
|
||||
mt_main_phases->SetValue("three phase");
|
||||
mt_main_phases_num->SetValue(3);
|
||||
}
|
||||
if (CAN_NIBL(0) == 3) {
|
||||
mt_main_phases->SetValue("not detected");
|
||||
mt_main_phases_num->SetValue(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x2B8A: { // AC mains voltage
|
||||
StandardMetrics.ms_v_charge_voltage->SetValue((float) (CAN_UINT(0) * 0.5), Volts);
|
||||
//ESP_LOGD(TAG, "2B8A EVC ms_v_charge_voltage: %f", (CAN_UINT(0) * 0.5));
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
char *buf = NULL;
|
||||
size_t rlen = len, offset = 0;
|
||||
do {
|
||||
rlen = FormatHexDump(&buf, data + offset, rlen, 16);
|
||||
offset += 16;
|
||||
ESP_LOGW(TAG, "OBD2: unhandled reply from EVC [%02x %02x]: %s", type, pid, buf ? buf : "-");
|
||||
} while (rlen);
|
||||
if (buf)
|
||||
free(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Date: 19th Nov 2022
|
||||
;
|
||||
; (C) 2022 Carsten Schmiemann
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
#include "vehicle_renaultzoe_ph2_can.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::IncomingHVAC(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x4009: { //Cabin temperature
|
||||
StandardMetrics.ms_v_env_cabintemp->SetValue(float((CAN_UINT(0) - 400) / 10), Celcius);
|
||||
//ESP_LOGD(TAG, "4361 HVAC ms_v_env_cabintemp: %f", float((CAN_UINT(0) - 400) / 10));
|
||||
break;
|
||||
}
|
||||
case 0x4360: { //Cabin setpoint
|
||||
StandardMetrics.ms_v_env_cabinsetpoint->SetValue(float(((CAN_NIBL(0) + 32) / 2)), Celcius);
|
||||
//ESP_LOGD(TAG, "4360 HVAC ms_v_env_cabinsetpoint: %d", (CAN_NIBL(0) + 32) / 2);
|
||||
break;
|
||||
}
|
||||
case 0x43D8: { //Compressor speed
|
||||
mt_hvac_compressor_speed->SetValue(float(CAN_UINT(0)));
|
||||
//ESP_LOGD(TAG, "43D8 HVAC mt_hvac_compressor_speed: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x4402: { //Compressor state
|
||||
if (CAN_NIBL(0) == 1) {
|
||||
mt_hvac_compressor_mode->SetValue("AC mode");
|
||||
StandardMetrics.ms_v_env_hvac->SetValue(true);
|
||||
}
|
||||
if (CAN_NIBL(0) == 2) {
|
||||
mt_hvac_compressor_mode->SetValue("De-ICE mode");
|
||||
StandardMetrics.ms_v_env_hvac->SetValue(true);
|
||||
}
|
||||
if (CAN_NIBL(0) == 4) {
|
||||
mt_hvac_compressor_mode->SetValue("Heat pump mode");
|
||||
StandardMetrics.ms_v_env_hvac->SetValue(true);
|
||||
}
|
||||
if (CAN_NIBL(0) == 6) {
|
||||
mt_hvac_compressor_mode->SetValue("Demisting mode");
|
||||
StandardMetrics.ms_v_env_hvac->SetValue(true);
|
||||
}
|
||||
if (CAN_NIBL(0) == 7) {
|
||||
mt_hvac_compressor_mode->SetValue("idle");
|
||||
StandardMetrics.ms_v_env_hvac->SetValue(false);
|
||||
}
|
||||
//ESP_LOGD(TAG, "%d HVAC mt_hvac_compressor_mode: %d", pid, CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x4369: { //Compressor pressure
|
||||
mt_hvac_compressor_pressure->SetValue(float(CAN_UINT(0) * 0.1));
|
||||
//ESP_LOGD(TAG, "%d HVAC mt_hvac_compressor_pressure: %f", pid, CAN_UINT(0) * 0.1);
|
||||
break;
|
||||
}
|
||||
case 0x4436: { //Compressor power
|
||||
mt_hvac_compressor_power->SetValue(float(CAN_UINT(0) * 25.0 / 100.0));
|
||||
//ESP_LOGD(TAG, "%d HVAC mt_hvac_compressor_power: %f", pid, CAN_UINT(0) * 25.0 / 100.0);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
char *buf = NULL;
|
||||
size_t rlen = len, offset = 0;
|
||||
do {
|
||||
rlen = FormatHexDump(&buf, data + offset, rlen, 16);
|
||||
offset += 16;
|
||||
ESP_LOGW(TAG, "OBD2: unhandled reply from HVAC [%02x %02x]: %s", type, pid, buf ? buf : "-");
|
||||
} while (rlen);
|
||||
if (buf)
|
||||
free(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Date: 19th Nov 2022
|
||||
;
|
||||
; (C) 2022 Carsten Schmiemann
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
#include "vehicle_renaultzoe_ph2_can.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::IncomingINV(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x700C: { // Inverter temperature
|
||||
StandardMetrics.ms_v_inv_temp->SetValue(float((CAN_UINT24(0) * 0.001953125) - 40), Celcius);
|
||||
//ESP_LOGD(TAG, "700C INV ms_v_inv_temp RAW: %f", float(CAN_UINT24(0)));
|
||||
//ESP_LOGD(TAG, "700C INV ms_v_inv_temp: %f", float((CAN_UINT24(0) * 0.001953125) - 40));
|
||||
break;
|
||||
}
|
||||
case 0x700F: { // Motor, Stator1 temperature
|
||||
StandardMetrics.ms_v_mot_temp->SetValue(float((CAN_UINT24(0) * 0.001953125) - 40), Celcius);
|
||||
mt_mot_temp_stator1->SetValue(float((CAN_UINT24(0) * 0.001953125) - 40), Celcius);
|
||||
//ESP_LOGD(TAG, "700F INV ms_v_mot_temp: %f", float((CAN_UINT24(0) * 0.001953125) - 40));
|
||||
break;
|
||||
}
|
||||
case 0x7010: { // Stator 2 temperature
|
||||
mt_mot_temp_stator2->SetValue(float((CAN_UINT24(0) * 0.001953125) - 40), Celcius);
|
||||
//ESP_LOGD(TAG, "7010 INV mt_mot_temp_stator2: %f", float((CAN_UINT24(0) * 0.001953125) - 40));
|
||||
break;
|
||||
}
|
||||
case 0x2004: { // Battery voltage sense
|
||||
mt_inv_hv_voltage->SetValue(float(CAN_UINT(0) * 0.03125), Volts);
|
||||
//ESP_LOGD(TAG, "2004 INV mt_inv_hv_voltage: %f", float(CAN_UINT(0) * 0.03125));
|
||||
StandardMetrics.ms_v_inv_power->SetValue(float (mt_inv_hv_voltage->AsFloat() * mt_inv_hv_current->AsFloat()) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x7049: { // Battery current sense
|
||||
mt_inv_hv_current->SetValue(float((CAN_UINT(0) * 0.03125) - 500), Amps);
|
||||
//ESP_LOGD(TAG, "7049 INV mt_inv_hv_current: %f", float(CAN_UINT(0) * 0.003125) - 500);
|
||||
StandardMetrics.ms_v_inv_power->SetValue(float (mt_inv_hv_current->AsFloat() * mt_inv_hv_voltage->AsFloat()) * 0.001);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
char *buf = NULL;
|
||||
size_t rlen = len, offset = 0;
|
||||
do {
|
||||
rlen = FormatHexDump(&buf, data + offset, rlen, 16);
|
||||
offset += 16;
|
||||
ESP_LOGW(TAG, "OBD2: unhandled reply from INV [%02x %02x]: %s", type, pid, buf ? buf : "-");
|
||||
} while (rlen);
|
||||
if (buf)
|
||||
free(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
641
OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/LBC_pids.cpp
Normal file
641
OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/LBC_pids.cpp
Normal file
|
@ -0,0 +1,641 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Date: 19th Nov 2022
|
||||
;
|
||||
; (C) 2022 Carsten Schmiemann
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
#include "vehicle_renaultzoe_ph2_can.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::IncomingLBC(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x9005: { //Battery voltage
|
||||
StandardMetrics.ms_v_bat_voltage->SetValue((float) (CAN_UINT(0) * 0.1), Volts);
|
||||
//ESP_LOGD(TAG, "9005 LBC ms_v_bat_voltage: %f", CAN_UINT(0) * 0.1);
|
||||
StandardMetrics.ms_v_bat_power->SetValue(((CAN_UINT(0) * 0.1) * StandardMetrics.ms_v_bat_current->AsFloat()) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x925D: { //Battery current
|
||||
StandardMetrics.ms_v_bat_current->SetValue((float) ((CAN_UINT(0) * 0.03125 - 1020) * -1.0f), Amps);
|
||||
//ESP_LOGD(TAG, "925D LBC ms_v_bat_current: %f", (CAN_UINT(0) * 0.03125 - 1020));
|
||||
StandardMetrics.ms_v_bat_power->SetValue((((CAN_UINT(0) * 0.03125 - 1020) * -1.0f) * StandardMetrics.ms_v_bat_voltage->AsFloat()) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9012: { //Battery average temperature
|
||||
StandardMetrics.ms_v_bat_temp->SetValue((float) (CAN_UINT(0) * 0.0625 - 40), Celcius);
|
||||
//ESP_LOGD(TAG, "9012 LBC ms_v_bat_temp: %f", (CAN_UINT(0) * 0.0625 - 40));
|
||||
break;
|
||||
}
|
||||
case 0x9002: { //Battery SOC
|
||||
StandardMetrics.ms_v_bat_soc->SetValue((float) (CAN_UINT(0)) * 0.01, Percentage);
|
||||
StandardMetrics.ms_v_bat_cac->SetValue(Bat_cell_capacity * CAN_UINT(0) * 0.0001);
|
||||
//ESP_LOGD(TAG, "9002 LBC mt_bat_lbc_soc: %f", bat_soc);
|
||||
break;
|
||||
}
|
||||
case 0x9003: { //Battery SOH
|
||||
StandardMetrics.ms_v_bat_soh->SetValue((float) (CAN_UINT(0) * 0.01), Percentage);
|
||||
//ESP_LOGD(TAG, "9003 LBC ms_v_bat_soh: %f", CAN_UINT(0) * 0.01);
|
||||
break;
|
||||
}
|
||||
case 0x9243: { //Battery energy charged kWh
|
||||
StandardMetrics.ms_v_charge_kwh_grid_total->SetValue((float) (CAN_UINT32(0) * 0.001), kWh);
|
||||
//ESP_LOGD(TAG, "9243 LBC ms_v_charge_kwh_grid_total: %f", CAN_UINT32(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9245: { //Battery energy discharged kWh
|
||||
StandardMetrics.ms_v_bat_energy_used_total->SetValue((float) (CAN_UINT32(0) * 0.001), kWh);
|
||||
//ESP_LOGD(TAG, "9244 LBC ms_v_bat_energy_used_total: %f", CAN_UINT32(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9247: { //Battery energy regenerated kWh
|
||||
StandardMetrics.ms_v_bat_energy_recd_total->SetValue((float) (CAN_UINT32(0) * 0.001), kWh);
|
||||
//ESP_LOGD(TAG, "9246 LBC ms_v_bat_energy_recd_total: %f", CAN_UINT32(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9210: { //Number of charge cycles
|
||||
mt_bat_cycles->SetValue(CAN_UINT(0));
|
||||
//ESP_LOGD(TAG, "9210 LBC mt_bat_cycles: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x9018: { //Max charge power
|
||||
mt_bat_max_charge_power->SetValue((float) (CAN_UINT(0) * 0.01), kW);
|
||||
//ESP_LOGD(TAG, "9018 LBC mt_bat_max_charge_power: %f", CAN_UINT(0) * 0.01);
|
||||
break;
|
||||
}
|
||||
case 0x91C8: { //Available charge in kWh
|
||||
mt_bat_available_energy->SetValue(float(CAN_UINT24(0) * 0.001), kWh);
|
||||
//ESP_LOGD(TAG, "91C8 LBC mt_bat_available_energy: %f", CAN_UINT24(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9131: {
|
||||
BmsSetCellTemperature(0, CAN_UINT(0) * 0.0625 - 40);
|
||||
//ESP_LOGD(TAG, "%x: %f C", pid, CAN_UINT(0) * 0.0625 - 40);
|
||||
break;
|
||||
}
|
||||
case 0x9132: {
|
||||
BmsSetCellTemperature(1, CAN_UINT(0) * 0.0625 - 40);
|
||||
//ESP_LOGD(TAG, "%x: %f C", pid, CAN_UINT(0) * 0.0625 - 40);
|
||||
break;
|
||||
}
|
||||
case 0x9133: {
|
||||
BmsSetCellTemperature(2, CAN_UINT(0) * 0.0625 - 40);
|
||||
//ESP_LOGD(TAG, "%x: %f C", pid, CAN_UINT(0) * 0.0625 - 40);
|
||||
break;
|
||||
}
|
||||
case 0x9134: {
|
||||
BmsSetCellTemperature(3, CAN_UINT(0) * 0.0625 - 40);
|
||||
//ESP_LOGD(TAG, "%x: %f C", pid, CAN_UINT(0) * 0.0625 - 40);
|
||||
break;
|
||||
}
|
||||
case 0x9135: {
|
||||
BmsSetCellTemperature(4, CAN_UINT(0) * 0.0625 - 40);
|
||||
//ESP_LOGD(TAG, "%x: %f C", pid, CAN_UINT(0) * 0.0625 - 40);
|
||||
break;
|
||||
}
|
||||
case 0x9136: {
|
||||
BmsSetCellTemperature(5, CAN_UINT(0) * 0.0625 - 40);
|
||||
//ESP_LOGD(TAG, "%x: %f C", pid, CAN_UINT(0) * 0.0625 - 40);
|
||||
break;
|
||||
}
|
||||
case 0x9137: {
|
||||
BmsSetCellTemperature(6, CAN_UINT(0) * 0.0625 - 40);
|
||||
//ESP_LOGD(TAG, "%x: %f C", pid, CAN_UINT(0) * 0.0625 - 40);
|
||||
break;
|
||||
}
|
||||
case 0x9138: {
|
||||
BmsSetCellTemperature(7, CAN_UINT(0) * 0.0625 - 40);
|
||||
//ESP_LOGD(TAG, "%x: %f C", pid, CAN_UINT(0) * 0.0625 - 40);
|
||||
break;
|
||||
}
|
||||
case 0x9139: {
|
||||
BmsSetCellTemperature(8, CAN_UINT(0) * 0.0625 - 40);
|
||||
//ESP_LOGD(TAG, "%x: %f C", pid, CAN_UINT(0) * 0.0625 - 40);
|
||||
break;
|
||||
}
|
||||
case 0x913A: {
|
||||
BmsSetCellTemperature(9, CAN_UINT(0) * 0.0625 - 40);
|
||||
//ESP_LOGD(TAG, "%x: %f C", pid, CAN_UINT(0) * 0.0625 - 40);
|
||||
break;
|
||||
}
|
||||
case 0x913B: {
|
||||
BmsSetCellTemperature(10, CAN_UINT(0) * 0.0625 - 40);
|
||||
//ESP_LOGD(TAG, "%x: %f C", pid, CAN_UINT(0) * 0.0625 - 40);
|
||||
break;
|
||||
}
|
||||
case 0x913C: {
|
||||
BmsSetCellTemperature(11, CAN_UINT(0) * 0.0625 - 40);
|
||||
//ESP_LOGD(TAG, "%x: %f C", pid, CAN_UINT(0) * 0.0625 - 40);
|
||||
break;
|
||||
}
|
||||
case 0x9021: {
|
||||
BmsSetCellVoltage(0, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9022: {
|
||||
BmsSetCellVoltage(1, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9023: {
|
||||
BmsSetCellVoltage(2, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9024: {
|
||||
BmsSetCellVoltage(3, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9025: {
|
||||
BmsSetCellVoltage(4, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9026: {
|
||||
BmsSetCellVoltage(5, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9027: {
|
||||
BmsSetCellVoltage(6, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9028: {
|
||||
BmsSetCellVoltage(7, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9029: {
|
||||
BmsSetCellVoltage(8, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x902A: {
|
||||
BmsSetCellVoltage(9, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x902B: {
|
||||
BmsSetCellVoltage(10, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x902C: {
|
||||
BmsSetCellVoltage(11, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x902D: {
|
||||
BmsSetCellVoltage(12, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x902E: {
|
||||
BmsSetCellVoltage(13, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x902F: {
|
||||
BmsSetCellVoltage(14, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9030: {
|
||||
BmsSetCellVoltage(15, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9031: {
|
||||
BmsSetCellVoltage(16, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9032: {
|
||||
BmsSetCellVoltage(17, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9033: {
|
||||
BmsSetCellVoltage(18, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9034: {
|
||||
BmsSetCellVoltage(19, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9035: {
|
||||
BmsSetCellVoltage(20, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9036: {
|
||||
BmsSetCellVoltage(21, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9037: {
|
||||
BmsSetCellVoltage(22, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9038: {
|
||||
BmsSetCellVoltage(23, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9039: {
|
||||
BmsSetCellVoltage(24, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x903A: {
|
||||
BmsSetCellVoltage(25, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x903B: {
|
||||
BmsSetCellVoltage(26, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x903C: {
|
||||
BmsSetCellVoltage(27, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x903D: {
|
||||
BmsSetCellVoltage(28, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x903E: {
|
||||
BmsSetCellVoltage(29, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x903F: {
|
||||
BmsSetCellVoltage(30, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9041: {
|
||||
BmsSetCellVoltage(31, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9042: {
|
||||
BmsSetCellVoltage(32, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9043: {
|
||||
BmsSetCellVoltage(33, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9044: {
|
||||
BmsSetCellVoltage(34, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9045: {
|
||||
BmsSetCellVoltage(35, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9046: {
|
||||
BmsSetCellVoltage(36, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9047: {
|
||||
BmsSetCellVoltage(37, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9048: {
|
||||
BmsSetCellVoltage(38, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9049: {
|
||||
BmsSetCellVoltage(39, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x904A: {
|
||||
BmsSetCellVoltage(40, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x904B: {
|
||||
BmsSetCellVoltage(41, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x904C: {
|
||||
BmsSetCellVoltage(42, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x904D: {
|
||||
BmsSetCellVoltage(43, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x904E: {
|
||||
BmsSetCellVoltage(44, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x904F: {
|
||||
BmsSetCellVoltage(45, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9050: {
|
||||
BmsSetCellVoltage(46, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9051: {
|
||||
BmsSetCellVoltage(47, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9052: {
|
||||
BmsSetCellVoltage(48, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9053: {
|
||||
BmsSetCellVoltage(49, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9054: {
|
||||
BmsSetCellVoltage(50, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9055: {
|
||||
BmsSetCellVoltage(51, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9056: {
|
||||
BmsSetCellVoltage(52, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9057: {
|
||||
BmsSetCellVoltage(53, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9058: {
|
||||
BmsSetCellVoltage(54, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9059: {
|
||||
BmsSetCellVoltage(55, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x905A: {
|
||||
BmsSetCellVoltage(56, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x905B: {
|
||||
BmsSetCellVoltage(57, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x905C: {
|
||||
BmsSetCellVoltage(58, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x905D: {
|
||||
BmsSetCellVoltage(59, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x905E: {
|
||||
BmsSetCellVoltage(60, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x905F: {
|
||||
BmsSetCellVoltage(61, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9061: {
|
||||
BmsSetCellVoltage(62, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9062: {
|
||||
BmsSetCellVoltage(63, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9063: {
|
||||
BmsSetCellVoltage(64, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9064: {
|
||||
BmsSetCellVoltage(65, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9065: {
|
||||
BmsSetCellVoltage(66, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9066: {
|
||||
BmsSetCellVoltage(67, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9067: {
|
||||
BmsSetCellVoltage(68, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9068: {
|
||||
BmsSetCellVoltage(69, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9069: {
|
||||
BmsSetCellVoltage(70, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x906A: {
|
||||
BmsSetCellVoltage(71, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x906B: {
|
||||
BmsSetCellVoltage(72, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x906C: {
|
||||
BmsSetCellVoltage(73, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x906D: {
|
||||
BmsSetCellVoltage(74, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x906E: {
|
||||
BmsSetCellVoltage(75, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x906F: {
|
||||
BmsSetCellVoltage(76, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9070: {
|
||||
BmsSetCellVoltage(77, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9071: {
|
||||
BmsSetCellVoltage(78, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9072: {
|
||||
BmsSetCellVoltage(79, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9073: {
|
||||
BmsSetCellVoltage(80, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9074: {
|
||||
BmsSetCellVoltage(81, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9075: {
|
||||
BmsSetCellVoltage(82, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9076: {
|
||||
BmsSetCellVoltage(83, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9077: {
|
||||
BmsSetCellVoltage(84, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9078: {
|
||||
BmsSetCellVoltage(85, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9079: {
|
||||
BmsSetCellVoltage(86, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x907A: {
|
||||
BmsSetCellVoltage(87, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x907B: {
|
||||
BmsSetCellVoltage(88, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x907C: {
|
||||
BmsSetCellVoltage(89, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x907D: {
|
||||
BmsSetCellVoltage(90, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x907E: {
|
||||
BmsSetCellVoltage(91, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x907F: {
|
||||
BmsSetCellVoltage(92, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9081: {
|
||||
BmsSetCellVoltage(93, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9082: {
|
||||
BmsSetCellVoltage(94, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
case 0x9083: {
|
||||
BmsSetCellVoltage(95, CAN_UINT(0) * 0.001);
|
||||
//ESP_LOGD(TAG, "%x: %f V", pid, CAN_UINT(0) * 0.001);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
char *buf = NULL;
|
||||
size_t rlen = len, offset = 0;
|
||||
do {
|
||||
rlen = FormatHexDump(&buf, data + offset, rlen, 16);
|
||||
offset += 16;
|
||||
ESP_LOGW(TAG, "OBD2: unhandled reply from LBC [%02x %02x]: %s", type, pid, buf ? buf : "-");
|
||||
} while (rlen);
|
||||
if (buf)
|
||||
free(buf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Date: 15th Apr 2022
|
||||
; Date: 19th Nov 2022
|
||||
;
|
||||
; (C) 2022 Carsten Schmiemann
|
||||
;
|
||||
|
@ -22,17 +22,16 @@
|
|||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
#include "vehicle_renaultzoe_ph2_can.h"
|
||||
|
||||
#include "vehicle_renaultzoe_ph2.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::IncomingCLUSTER(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x2101: { // Cluster - trip counter
|
||||
mt_pos_car_trip->SetValue(CAN_UINT32(0), Kilometers);
|
||||
ESP_LOGD(TAG, "2101 CLUSTER mt_pos_car_trip: %f", float(CAN_UINT32(0)));
|
||||
//working very unreliable
|
||||
break;
|
||||
}
|
||||
void OvmsVehicleRenaultZoePh2CAN::IncomingUCM(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x6079: { //12V Battery Current
|
||||
StandardMetrics.ms_v_charge_12v_current->SetValue((float) (CAN_UINT(0) * 0.1), Amps);
|
||||
StandardMetrics.ms_v_bat_12v_current->SetValue((float) (CAN_UINT(0) * 0.1), Amps);
|
||||
//ESP_LOGD(TAG, "6079 UCM ms_v_charge_12v_current: %f", CAN_UINT(0) * 0.1);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
char *buf = NULL;
|
||||
|
@ -40,7 +39,7 @@ void OvmsVehicleRenaultZoePh2::IncomingCLUSTER(uint16_t type, uint16_t pid, cons
|
|||
do {
|
||||
rlen = FormatHexDump(&buf, data + offset, rlen, 16);
|
||||
offset += 16;
|
||||
ESP_LOGW(TAG, "OBD2: unhandled reply from CLUSTER [%02x %02x]: %s", type, pid, buf ? buf : "-");
|
||||
ESP_LOGW(TAG, "OBD2: unhandled reply from UCM [%02x %02x]: %s", type, pid, buf ? buf : "-");
|
||||
} while (rlen);
|
||||
if (buf)
|
||||
free(buf);
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Date: 19th Nov 2022
|
||||
;
|
||||
; (C) 2022 Carsten Schmiemann
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
#include "ovms_log.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include "pcp.h"
|
||||
#include "ovms_metrics.h"
|
||||
#include "ovms_events.h"
|
||||
#include "ovms_config.h"
|
||||
#include "ovms_command.h"
|
||||
#include "metrics_standard.h"
|
||||
#include "ovms_notify.h"
|
||||
#include "ovms_peripherals.h"
|
||||
#include "ovms_netmanager.h"
|
||||
|
||||
#include "vehicle_renaultzoe_ph2_can.h"
|
||||
#include "ph2_poller.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::CanInit()
|
||||
{
|
||||
OvmsCommand* cmd;
|
||||
OvmsCommand* ph2;
|
||||
ph2 = cmd_zoe_ph2->RegisterCommand("ph2", "Zoe Ph2 CAN tools");
|
||||
cmd = ph2->RegisterCommand("request", "Send ISO-TP request, output response");
|
||||
cmd->RegisterCommand("device", "Send ISO-TP request to a ECU", shell_can_request, "<txid> <rxid> <request>", 3, 3);
|
||||
cmd->RegisterCommand("broadcast", "Send ISO-TP request as broadcast", shell_can_request, "<request>", 1, 1);
|
||||
}
|
||||
|
||||
int OvmsVehicleRenaultZoePh2CAN::CanRequest(uint16_t txid, uint16_t rxid, string request, string& response, int timeout_ms /*=3000*/)
|
||||
{
|
||||
OvmsMutexLock lock(&zoe_can1_request);
|
||||
|
||||
// prepare single poll:
|
||||
OvmsVehicle::poll_pid_t poll[] = {
|
||||
{ txid, rxid, 0, 0, { 1, 1, 1 }, 0, ISOTP_STD },
|
||||
POLL_LIST_END
|
||||
};
|
||||
|
||||
assert(request.size() > 0);
|
||||
poll[0].type = request[0];
|
||||
|
||||
if (POLL_TYPE_HAS_16BIT_PID(poll[0].type)) {
|
||||
assert(request.size() >= 3);
|
||||
poll[0].args.pid = request[1] << 8 | request[2];
|
||||
poll[0].args.datalen = LIMIT_MAX(request.size()-3, sizeof(poll[0].args.data));
|
||||
memcpy(poll[0].args.data, request.data()+3, poll[0].args.datalen);
|
||||
}
|
||||
else if (POLL_TYPE_HAS_8BIT_PID(poll[0].type)) {
|
||||
assert(request.size() >= 2);
|
||||
poll[0].args.pid = request.at(1);
|
||||
poll[0].args.datalen = LIMIT_MAX(request.size()-2, sizeof(poll[0].args.data));
|
||||
memcpy(poll[0].args.data, request.data()+2, poll[0].args.datalen);
|
||||
}
|
||||
else {
|
||||
poll[0].args.pid = 0;
|
||||
poll[0].args.datalen = LIMIT_MAX(request.size()-1, sizeof(poll[0].args.data));
|
||||
memcpy(poll[0].args.data, request.data()+1, poll[0].args.datalen);
|
||||
}
|
||||
|
||||
// stop default polling:
|
||||
PollSetPidList(m_can1, NULL);
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// clear rx semaphore, start single poll:
|
||||
zoe_can1_rxwait.Take(0);
|
||||
PollSetPidList(m_can1, poll);
|
||||
|
||||
// wait for response:
|
||||
bool rxok = zoe_can1_rxwait.Take(pdMS_TO_TICKS(timeout_ms));
|
||||
if (rxok == pdTRUE)
|
||||
response = zoe_can1_rxbuf;
|
||||
|
||||
// restore default polling:
|
||||
zoe_can1_rxwait.Give();
|
||||
PollSetPidList(m_can1, renault_zoe_polls);
|
||||
|
||||
return (rxok == pdFALSE) ? -1 : (int)zoe_can1_rxerr;
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::shell_can_request(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv)
|
||||
{
|
||||
OvmsVehicleRenaultZoePh2CAN* zoe_ph2_can = GetInstance(writer);
|
||||
uint16_t txid = 0, rxid = 0;
|
||||
string request;
|
||||
string response;
|
||||
|
||||
// parse args:
|
||||
string device = cmd->GetName();
|
||||
if (device == "device") {
|
||||
if (argc < 3) {
|
||||
writer->puts("ERROR: too few args, need: txid rxid request");
|
||||
return;
|
||||
}
|
||||
txid = strtol(argv[0], NULL, 16);
|
||||
rxid = strtol(argv[1], NULL, 16);
|
||||
request = hexdecode(argv[2]);
|
||||
} else {
|
||||
if (argc < 1) {
|
||||
writer->puts("ERROR: too few args, need: request");
|
||||
return;
|
||||
}
|
||||
request = hexdecode(argv[0]);
|
||||
// "broadcast"
|
||||
txid = 0x7df;
|
||||
rxid = 0;
|
||||
}
|
||||
|
||||
// validate request:
|
||||
if (request.size() == 0) {
|
||||
writer->puts("ERROR: no request");
|
||||
return;
|
||||
} else {
|
||||
uint8_t type = request.at(0);
|
||||
if ((POLL_TYPE_HAS_16BIT_PID(type) && request.size() < 3) ||
|
||||
(POLL_TYPE_HAS_8BIT_PID(type) && request.size() < 2)) {
|
||||
writer->printf("ERROR: request too short for type %02X\n", type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// execute request:
|
||||
int err = zoe_ph2_can->CanRequest(txid, rxid, request, response, 3000);
|
||||
if (err == -1) {
|
||||
writer->puts("ERROR: timeout waiting for response");
|
||||
return;
|
||||
} else if (err) {
|
||||
writer->printf("ERROR: request failed with response error code %02X\n", err);
|
||||
return;
|
||||
}
|
||||
|
||||
// output response as hex dump:
|
||||
writer->puts("Response:");
|
||||
char *buf = NULL;
|
||||
size_t rlen = response.size(), offset = 0;
|
||||
do {
|
||||
rlen = FormatHexDump(&buf, response.data() + offset, rlen, 16);
|
||||
offset += 16;
|
||||
writer->puts(buf ? buf : "-");
|
||||
} while (rlen);
|
||||
if (buf)
|
||||
free(buf);
|
||||
}
|
||||
|
||||
OvmsVehicle::vehicle_command_t OvmsVehicleRenaultZoePh2CAN::CommandPreHeat(bool climatecontrolon) {
|
||||
|
||||
//Wake Up Packet
|
||||
uint8_t data[8] = {0x83, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
canbus *obd;
|
||||
obd = m_can1;
|
||||
|
||||
for (int i=0; i<40; i++)
|
||||
{
|
||||
obd->WriteStandard(0x55C, 8, data);
|
||||
}
|
||||
obd->WriteStandard(0x6f9, 8, data);
|
||||
data[0] = 0x40;
|
||||
data[1] = 0x80;
|
||||
|
||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||
obd->WriteStandard(0x43c, 8, data);
|
||||
|
||||
data = {0xe4, 0x64, 0x70, 0x00, 0x28, 0x84, 0x07, 0x10};
|
||||
obd->WriteStandard(0x46f, 8, data);
|
||||
|
||||
data = {0x84, 0xc7, 0x07, 0x55, 0xe0, 0x0d, 0x00, 0xc4};
|
||||
obd->WriteStandard(0x47d, 8, data);
|
||||
|
||||
data = {0x03, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
obd->WriteStandard(0x46a, 8, data);
|
||||
|
||||
data = {0x03, 0x02, 0x04, 0x02, 0x06, 0x00, 0x20, 0x08};
|
||||
obd->WriteStandard(0x46c, 8, data);
|
||||
|
||||
data = {0x10, 0xc9, 0x50, 0x21, 0x01, 0x20, 0x00, 0x00};
|
||||
obd->WriteStandard(0x482, 8, data);
|
||||
|
||||
data = {0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00};
|
||||
obd->WriteStandard(0x5b1, 8, data);
|
||||
|
||||
data = {0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00};
|
||||
obd->WriteStandard(0x5ba, 8, data);
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
OvmsVehicle::vehicle_command_t OvmsVehicleRenaultZoePh2CAN::CommandWakeup() {
|
||||
ESP_LOGI(TAG, "Send Wakeup Command");
|
||||
|
||||
vTaskDelay(500 / portTICK_PERIOD_MS);
|
||||
|
||||
uint32_t txid = 0x747, rxid = 0x767; //IVI
|
||||
uint8_t protocol = ISOTP_STD;
|
||||
int timeout_ms = 100;
|
||||
std::string request;
|
||||
std::string response;
|
||||
|
||||
request = hexdecode("2F90090301");
|
||||
int err = PollSingleRequest(m_can1, txid, rxid, request, response, timeout_ms, protocol);
|
||||
|
||||
request = hexdecode("2F900900");
|
||||
err = PollSingleRequest(m_can1, txid, rxid, request, response, timeout_ms, protocol);
|
||||
|
||||
if (err == POLLSINGLE_TXFAILURE) {
|
||||
ESP_LOGE(TAG, "ERROR: transmission failure (CAN bus error)");
|
||||
return Fail;
|
||||
}
|
||||
else if (err < 0) {
|
||||
ESP_LOGD(TAG, "ERROR: timeout waiting for poller/response");
|
||||
return Fail;
|
||||
}
|
||||
else if (err) {
|
||||
ESP_LOGD(TAG, "ERROR: request failed with response error code %02X\n", err);
|
||||
return Fail;
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
OvmsVehicle::vehicle_command_t OvmsVehicleRenaultZoePh2CAN::CommandLock(const char* pin) {
|
||||
//ToDo: Sniff HFM/BCM packets
|
||||
return NotImplemented;
|
||||
}
|
||||
|
||||
OvmsVehicle::vehicle_command_t OvmsVehicleRenaultZoePh2CAN::CommandUnlock(const char* pin) {
|
||||
//ToDo: Sniff HFM/BCM packets
|
||||
return NotImplemented;
|
||||
}
|
224
OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/ph2_poller.h
Normal file
224
OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/ph2_poller.h
Normal file
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Date: 19th Nov 2022
|
||||
;
|
||||
; (C) 2022 Carsten Schmiemann
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#define SESSION_EXTDIAG 0x1003
|
||||
#define SESSION_DEFAULT 0x1001
|
||||
#define SESSION_AfterSales 0x10C0
|
||||
|
||||
// Pollstate 0 - POLLSTATE_OFF - car is off
|
||||
// Pollstate 1 - POLLSTATE_ON - car is on
|
||||
// Pollstate 2 - POLLSTATE_DRIVING - car is driving
|
||||
// Pollstate 3 - POLLSTATE_CHARGING - car is charging
|
||||
static const OvmsVehicle::poll_pid_t renault_zoe_polls[] = {
|
||||
//***TX-ID, ***RX-ID, ***SID, ***PID, { Polltime (seconds) for Pollstate 0, 1, 2, 3}, ***CAN BUS Interface, ***FRAMETYPE
|
||||
|
||||
//Motor Inverter
|
||||
//{ 0x18dadff1, 0x18daf1df, VEHICLE_POLL_TYPE_OBDIISESSION, SESSION_EXTDIAG, { 0, 60, 60, 60 }, 0, ISOTP_EXTFRAME }, // OBD Extended Diagnostic Session
|
||||
{ 0x18dadff1, 0x18daf1df, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x700C, { 0, 10, 10, 10 }, 0, ISOTP_EXTFRAME }, // Inverter temperature
|
||||
{ 0x18dadff1, 0x18daf1df, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x700F, { 0, 10, 10, 10 }, 0, ISOTP_EXTFRAME }, // Stator Temperature 1
|
||||
{ 0x18dadff1, 0x18daf1df, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x7010, { 0, 10, 10, 10 }, 0, ISOTP_EXTFRAME }, // Stator Temperature 2
|
||||
{ 0x18dadff1, 0x18daf1df, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2004, { 0, 60, 3, 60 }, 0, ISOTP_EXTFRAME }, // Battery voltage sense
|
||||
{ 0x18dadff1, 0x18daf1df, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x7049, { 0, 60, 3, 60 }, 0, ISOTP_EXTFRAME }, // Current voltage sense
|
||||
|
||||
//EVC-HCM-VCM
|
||||
//{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIISESSION, SESSION_EXTDIAG, { 0, 60, 60, 60 }, 0, ISOTP_EXTFRAME }, // OBD Extended Diagnostic Session
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2006, { 0, 10, 10, 300 }, 0, ISOTP_EXTFRAME }, // Odometer
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2003, { 0, 60, 2, 300 }, 0, ISOTP_EXTFRAME }, // Vehicle Speed
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2005, { 0, 10, 10, 10 }, 0, ISOTP_EXTFRAME }, // 12Battery Voltage
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x21CF, { 0, 2, 10, 300 }, 0, ISOTP_EXTFRAME }, // Inverter Status
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2218, { 0, 20, 20, 20 }, 0, ISOTP_EXTFRAME }, // Ambient air temperature
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2A09, { 0, 10, 10, 10 }, 0, ISOTP_EXTFRAME }, // Power usage by consumer
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2191, { 0, 10, 10, 10 }, 0, ISOTP_EXTFRAME }, // Power usage by ptc
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2B85, { 0, 2, 300, 10 }, 0, ISOTP_EXTFRAME }, // Charge plug present
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2B6D, { 0, 2, 300, 10 }, 0, ISOTP_EXTFRAME }, // Charge MMI states
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2B7A, { 0, 2, 300, 10 }, 0, ISOTP_EXTFRAME }, // Charge type
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x3064, { 0, 10, 3, 10 }, 0, ISOTP_EXTFRAME }, // Motor rpm
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x300F, { 0, 2, 300, 3 }, 0, ISOTP_EXTFRAME }, // AC charging power available
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x300D, { 0, 10, 300, 3 }, 0, ISOTP_EXTFRAME }, // AC mains current
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x300B, { 0, 2, 300, 10 }, 0, ISOTP_EXTFRAME }, // AC phases
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2B8A, { 0, 2, 300, 10 }, 0, ISOTP_EXTFRAME }, // AC mains voltage
|
||||
|
||||
//BCM
|
||||
//{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIISESSION, SESSION_DEFAULT, { 0, 60, 60, 60 }, 0, ISOTP_STD }, // OBD Extended Diagnostic Session
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6300, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS pressure - front left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6301, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS pressure - front right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6302, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS pressure - rear left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6303, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS pressure - rear right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6310, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS temp - front left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6311, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS temp - front right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6312, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS temp - rear left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6313, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS temp - rear right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4109, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS alert - front left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x410A, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS alert - front right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x410B, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS alert - rear left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x410C, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS alert - rear right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x8004, { 0, 3, 3, 3 }, 0, ISOTP_STD }, // Car secure aka vehicle locked
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6026, { 0, 3, 3, 3 }, 0, ISOTP_STD }, // Front left door
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6027, { 0, 3, 3, 3 }, 0, ISOTP_STD }, // Front right door
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x61B2, { 0, 3, 3, 3 }, 0, ISOTP_STD }, // Rear left door
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x61B3, { 0, 3, 3, 3 }, 0, ISOTP_STD }, // Rear right door
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x609B, { 0, 3, 3, 3 }, 0, ISOTP_STD }, // Tailgate
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4186, { 0, 3, 3, 3 }, 0, ISOTP_STD }, // Low beam lights
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x60C6, { 0, 3, 6, 60 }, 0, ISOTP_STD }, // Ignition relay (switch), working but behavior on CHARING testing needed
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4060, { 0, 600, 0, 0 }, 0, ISOTP_STD }, // Vehicle identificaftion number
|
||||
|
||||
//LBC
|
||||
//{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIISESSION, SESSION_DEFAULT, { 0, 60, 60, 60 }, 0, ISOTP_EXTFRAME }, // OBD Extended Diagnostic Session
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9002, { 0, 10, 10, 10 }, 0, ISOTP_EXTFRAME }, // SOC
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9003, { 0, 60, 60, 10 }, 0, ISOTP_EXTFRAME }, // SOH
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9005, { 0, 10, 3, 5 }, 0, ISOTP_EXTFRAME }, // Battery Voltage
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x925D, { 0, 10, 3, 5 }, 0, ISOTP_EXTFRAME }, // Battery Current
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9012, { 0, 10, 60, 5 }, 0, ISOTP_EXTFRAME }, // Battery Average Temperature
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x91C8, { 0, 60, 60, 5 }, 0, ISOTP_EXTFRAME }, // Battery Available Energy kWh
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9243, { 0, 60, 60, 10 }, 0, ISOTP_EXTFRAME }, // Energy charged kWh
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9245, { 0, 60, 10, 60 }, 0, ISOTP_EXTFRAME }, // Energy discharged kWh
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9247, { 0, 60, 10, 60 }, 0, ISOTP_EXTFRAME }, // Energy regenerated kWh
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9210, { 0, 60, 60, 60 }, 0, ISOTP_EXTFRAME }, // Number of complete cycles
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9018, { 0, 10, 60, 10 }, 0, ISOTP_EXTFRAME }, // Max Charge Power
|
||||
//LBC Cell voltages and temperatures, OBD Grouppoll not working
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9131, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 1
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9132, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 2
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9133, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 3
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9134, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 4
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9135, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 5
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9136, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 6
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9137, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 7
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9138, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 8
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9139, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 9
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x913A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 10
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x913B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 11
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x913C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 12
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9021, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 1
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9022, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 2
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9023, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 3
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9024, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 4
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9025, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 5
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9026, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 6
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9027, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 7
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9028, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 8
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9029, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 9
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 10
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 11
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 12
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902D, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 13
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902E, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 14
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902F, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 15
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9030, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 16
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9031, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 17
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9032, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 18
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9033, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 19
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9034, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 20
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9035, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 21
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9036, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 22
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9037, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 23
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9038, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 24
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9039, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 25
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 26
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 27
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 28
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903D, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 29
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903E, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 30
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903F, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 31
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9041, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 32
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9042, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 33
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9043, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 34
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9044, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 35
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9045, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 36
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9046, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 37
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9047, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 38
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9048, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 39
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9049, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 40
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 41
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 42
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 43
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904D, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 44
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904E, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 45
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904F, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 46
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9050, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 47
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9051, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 48
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9052, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 49
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9053, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 50
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9054, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 51
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9055, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 52
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9056, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 53
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9057, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 54
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9058, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 55
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9059, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 56
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 57
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 58
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 59
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905D, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 60
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905E, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 61
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905F, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 62
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9061, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 63
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9062, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 64
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9063, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 65
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9064, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 66
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9065, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 67
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9066, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 68
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9067, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 69
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9068, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 70
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9069, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 71
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 72
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 73
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 74
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906D, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 75
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906E, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 76
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906F, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 77
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9070, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 78
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9071, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 79
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9072, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 80
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9073, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 81
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9074, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 82
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9075, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 83
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9076, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 84
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9077, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 85
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9078, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 86
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9079, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 87
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 88
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 89
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 90
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907D, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 91
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907E, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 92
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907F, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 93
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9081, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 94
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9082, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 95
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9083, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 96
|
||||
|
||||
//HVAC
|
||||
//{ 0x744, 0x764, VEHICLE_POLL_TYPE_OBDIISESSION, SESSION_EXTDIAG, { 0, 60, 60, 60 }, 0, ISOTP_STD }, // OBD Extended Diagnostic Session
|
||||
{ 0x744, 0x764, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4009, { 0, 10, 60, 10 }, 0, ISOTP_STD }, // Cabin temp
|
||||
{ 0x744, 0x764, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4360, { 0, 60, 60, 60 }, 0, ISOTP_STD }, // Cabin setpoint
|
||||
{ 0x744, 0x764, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x43D8, { 0, 10, 10, 5 }, 0, ISOTP_STD }, // Compressor speed
|
||||
{ 0x744, 0x764, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4402, { 0, 10, 10, 10 }, 0, ISOTP_STD }, // Compressor state
|
||||
{ 0x744, 0x764, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4369, { 0, 10, 10, 10 }, 0, ISOTP_STD }, // Compressor pressure in BAR
|
||||
{ 0x744, 0x764, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4436, { 0, 10, 10, 10 }, 0, ISOTP_STD }, // Compressor power
|
||||
|
||||
//UCM
|
||||
//{ 0x74D, 0x76D, VEHICLE_POLL_TYPE_OBDIISESSION, SESSION_AfterSales, { 0, 60, 60, 60 }, 0, ISOTP_STD }, // OBD Extended Diagnostic Session
|
||||
{ 0x74D, 0x76D, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6079, { 0, 10, 10, 10 }, 0, ISOTP_STD }, // 12V Battery current
|
||||
|
||||
POLL_LIST_END
|
||||
};
|
135
OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/rz2_web.cpp
Normal file
135
OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/rz2_web.cpp
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Date: 19th Nov 2022
|
||||
;
|
||||
; (C) 2022 Carsten Schmiemann
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sdkconfig.h>
|
||||
#ifdef CONFIG_OVMS_COMP_WEBSERVER
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include "ovms_metrics.h"
|
||||
#include "ovms_events.h"
|
||||
#include "ovms_config.h"
|
||||
#include "ovms_command.h"
|
||||
#include "metrics_standard.h"
|
||||
#include "ovms_notify.h"
|
||||
#include "ovms_webserver.h"
|
||||
|
||||
#include "vehicle_renaultzoe_ph2_can.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define _attr(text) (c.encode_html(text).c_str())
|
||||
#define _html(text) (c.encode_html(text).c_str())
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::WebCfgCommon(PageEntry_t& p, PageContext_t& c)
|
||||
{
|
||||
std::string error, rangeideal, battcapacity;
|
||||
bool UseBMScalculation;
|
||||
|
||||
if (c.method == "POST") {
|
||||
rangeideal = c.getvar("rangeideal");
|
||||
battcapacity = c.getvar("battcapacity");
|
||||
UseBMScalculation = (c.getvar("UseBMScalculation") == "no");
|
||||
|
||||
if (!rangeideal.empty()) {
|
||||
int v = atoi(rangeideal.c_str());
|
||||
if (v < 90 || v > 500)
|
||||
error += "<li data-input=\"rangeideal\">Range Ideal must be of 80…500 km</li>";
|
||||
}
|
||||
if (error == "") {
|
||||
// store:
|
||||
MyConfig.SetParamValue("xrz2c", "rangeideal", rangeideal);
|
||||
MyConfig.SetParamValue("xrz2c", "battcapacity", battcapacity);
|
||||
MyConfig.SetParamValueBool("xrz2c", "UseBMScalculation", UseBMScalculation);
|
||||
|
||||
c.head(200);
|
||||
c.alert("success", "<p class=\"lead\">Renault Zoe Ph2 battery setup saved.</p>");
|
||||
MyWebServer.OutputHome(p, c);
|
||||
c.done();
|
||||
return;
|
||||
}
|
||||
|
||||
error = "<p class=\"lead\">Error!</p><ul class=\"errorlist\">" + error + "</ul>";
|
||||
c.head(400);
|
||||
c.alert("danger", error.c_str());
|
||||
}
|
||||
else {
|
||||
// read configuration:
|
||||
rangeideal = MyConfig.GetParamValue("xrz2c", "rangeideal", "350");
|
||||
battcapacity = MyConfig.GetParamValue("xrz2c", "battcapacity", "52000");
|
||||
UseBMScalculation = MyConfig.GetParamValueBool("xrz2c", "UseBMScalculation", false);
|
||||
c.head(200);
|
||||
}
|
||||
|
||||
c.panel_start("primary", "Renault Zoe Ph2 Battery Setup");
|
||||
c.form_start(p.uri);
|
||||
|
||||
c.fieldset_start("Battery size and ideal range");
|
||||
|
||||
c.input_radio_start("Battery size", "battcapacity");
|
||||
c.input_radio_option("battcapacity", "R240 (22kWh)", "22000", battcapacity == "22000");
|
||||
c.input_radio_option("battcapacity", "ZE40 (41kWh)", "41000", battcapacity == "41000");
|
||||
c.input_radio_option("battcapacity", "ZE50 (52kWh)", "52000", battcapacity == "52000");
|
||||
c.input_radio_end("");
|
||||
|
||||
c.input_slider("Range Ideal", "rangeideal", 3, "km", -1, atoi(rangeideal.c_str()), 350, 80, 500, 1,
|
||||
"<p>Default 350km. Ideal Range...</p>");
|
||||
|
||||
c.fieldset_start("Battery energy calculation");
|
||||
|
||||
c.input_radio_start("Which energy calculation?", "UseBMScalculation");
|
||||
c.input_radio_option("UseBMScalculation", "OVMS energy calculation", "yes", UseBMScalculation == false);
|
||||
c.input_radio_option("UseBMScalculation", "BMS-based calculation", "no", UseBMScalculation == true);
|
||||
c.input_radio_end("");
|
||||
|
||||
c.fieldset_end();
|
||||
|
||||
c.print("<hr>");
|
||||
c.input_button("default", "Save");
|
||||
c.form_end();
|
||||
c.panel_end();
|
||||
c.done();
|
||||
}
|
||||
|
||||
/**
|
||||
* WebInit: register pages
|
||||
*/
|
||||
void OvmsVehicleRenaultZoePh2CAN::WebInit()
|
||||
{
|
||||
MyWebServer.RegisterPage("/xrz2c/battmon", "BMS View", OvmsWebServer::HandleBmsCellMonitor, PageMenu_Vehicle, PageAuth_Cookie);
|
||||
MyWebServer.RegisterPage("/xrz2c/settings", "Setup", WebCfgCommon, PageMenu_Vehicle, PageAuth_Cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* WebDeInit: deregister pages
|
||||
*/
|
||||
void OvmsVehicleRenaultZoePh2CAN::WebDeInit()
|
||||
{
|
||||
MyWebServer.DeregisterPage("/xrz2c/battmon");
|
||||
MyWebServer.DeregisterPage("/xrz2c/battery");
|
||||
}
|
||||
|
||||
|
||||
#endif //CONFIG_OVMS_COMP_WEBSERVER
|
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Date: 19th Nov 2022
|
||||
;
|
||||
; (C) 2022 Carsten Schmiemann
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
#include "ovms_log.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <iomanip>
|
||||
#include "pcp.h"
|
||||
#include "ovms_metrics.h"
|
||||
#include "ovms_events.h"
|
||||
#include "ovms_config.h"
|
||||
#include "ovms_command.h"
|
||||
#include "metrics_standard.h"
|
||||
#include "ovms_notify.h"
|
||||
#include "ovms_peripherals.h"
|
||||
#include "ovms_netmanager.h"
|
||||
|
||||
#include "vehicle_renaultzoe_ph2_can.h"
|
||||
#include "ph2_poller.h"
|
||||
|
||||
const char *OvmsVehicleRenaultZoePh2CAN::s_tag = "v-zoe-ph2-can";
|
||||
|
||||
OvmsVehicleRenaultZoePh2CAN::OvmsVehicleRenaultZoePh2CAN() {
|
||||
ESP_LOGI(TAG, "Start Renault Zoe Ph2 (CAN) vehicle module");
|
||||
|
||||
//Init variables supressing push on boot up
|
||||
StandardMetrics.ms_v_type->SetValue("RZ2");
|
||||
StandardMetrics.ms_v_charge_inprogress->SetValue(false);
|
||||
StandardMetrics.ms_v_charge_pilot->SetValue(false);
|
||||
StandardMetrics.ms_v_charge_state->SetValue("stopped");
|
||||
StandardMetrics.ms_v_charge_substate->SetValue("stopped");
|
||||
StandardMetrics.ms_v_env_on->SetValue(false);
|
||||
|
||||
MyConfig.RegisterParam("xrz2c", "Renault Zoe Ph2 (CAN) configuration", true, true);
|
||||
ConfigChanged(NULL);
|
||||
|
||||
// CAN1: Init Zoe Ph2 M-CAN bus
|
||||
RegisterCanBus(1, CAN_MODE_ACTIVE, CAN_SPEED_500KBPS);
|
||||
// CAN2: Init Zoe Ph2 EXT-CAN bus
|
||||
RegisterCanBus(2, CAN_MODE_LISTEN, CAN_SPEED_500KBPS);
|
||||
// CAN3: Init Zoe Ph2 V1-CAN bus
|
||||
RegisterCanBus(3, CAN_MODE_LISTEN, CAN_SPEED_500KBPS);
|
||||
|
||||
cmd_zoe_ph2 = MyCommandApp.RegisterCommand("xrz2c", "Renault Zoe Phase 2");
|
||||
CanInit();
|
||||
|
||||
POLLSTATE_OFF;
|
||||
ESP_LOGI(TAG, "Pollstate switched to OFF");
|
||||
|
||||
PollSetPidList(m_can1, renault_zoe_polls);
|
||||
PollSetThrottling(10);
|
||||
PollSetResponseSeparationTime(20);
|
||||
|
||||
// Renault ZOE specific metrics
|
||||
mt_bus_awake = MyMetrics.InitBool("zph2.v.bus.awake", SM_STALE_NONE, false);
|
||||
mt_pos_odometer_start = MyMetrics.InitFloat("zph2.v.pos.odometer.start", SM_STALE_MID, 0, Kilometers, true);
|
||||
mt_bat_used_start = MyMetrics.InitFloat("zph2.b.used.start", SM_STALE_MID, 0, kWh, true);
|
||||
mt_bat_recd_start = MyMetrics.InitFloat("zph2.b.recd.start", SM_STALE_MID, 0, kWh, true);
|
||||
mt_bat_chg_start = MyMetrics.InitFloat("zph2.b.chg.start", SM_STALE_MID, 0, kWh, true);
|
||||
mt_bat_available_energy = MyMetrics.InitFloat("zph2.b.avail.energy", SM_STALE_NONE, 0, kWh, true);
|
||||
mt_bat_aux_power_consumer = MyMetrics.InitFloat("zph2.b.aux.power.consumer", SM_STALE_MID, 0, Watts);
|
||||
mt_bat_aux_power_ptc = MyMetrics.InitFloat("zph2.b.aux.power.ptc", SM_STALE_MID, 0, Watts);
|
||||
mt_bat_max_charge_power = MyMetrics.InitFloat("zph2.b.max.charge.power", SM_STALE_MID, 0, kW, true);
|
||||
mt_bat_cycles = MyMetrics.InitFloat("zph2.b.cycles", SM_STALE_MID, 0, Other, true);
|
||||
mt_main_power_available = MyMetrics.InitFloat("zph2.c.main.power.available", SM_STALE_MIN, 0, kW);
|
||||
mt_main_phases = MyMetrics.InitString("zph2.c.main.phases", SM_STALE_MIN, 0);
|
||||
mt_main_phases_num = MyMetrics.InitFloat("zph2.c.main.phases.num", SM_STALE_MIN, 0);
|
||||
mt_inv_status = MyMetrics.InitString("zph2.m.inverter.status", SM_STALE_NONE, 0);
|
||||
mt_inv_hv_voltage = MyMetrics.InitFloat("zph2.i.voltage", SM_STALE_MID, 0, Volts, true);
|
||||
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);
|
||||
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);
|
||||
|
||||
// BMS configuration:
|
||||
BmsSetCellArrangementVoltage(96, 1);
|
||||
BmsSetCellArrangementTemperature(12, 1);
|
||||
BmsSetCellLimitsVoltage(2.0, 5.0);
|
||||
BmsSetCellLimitsTemperature(-39, 200);
|
||||
BmsSetCellDefaultThresholdsVoltage(0.030, 0.050);
|
||||
BmsSetCellDefaultThresholdsTemperature(4.0, 5.0);
|
||||
|
||||
#ifdef CONFIG_OVMS_COMP_WEBSERVER
|
||||
WebInit();
|
||||
#endif
|
||||
}
|
||||
|
||||
OvmsVehicleRenaultZoePh2CAN::~OvmsVehicleRenaultZoePh2CAN() {
|
||||
ESP_LOGI(TAG, "Stop Renault Zoe Ph2 (CAN) vehicle module");
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::ConfigChanged(OvmsConfigParam* param) {
|
||||
if (param && param->GetName() != "xrz2c")
|
||||
return;
|
||||
|
||||
// get values from config store
|
||||
m_range_ideal = MyConfig.GetParamValueInt("xrz2c", "rangeideal", 350);
|
||||
m_battery_capacity = MyConfig.GetParamValueInt("xrz2c", "battcapacity", 52000);
|
||||
m_UseBMScalculation = MyConfig.GetParamValueBool("xrz2c", "UseBMScalculation", false);
|
||||
StandardMetrics.ms_v_bat_range_ideal->SetValue(m_range_ideal, Kilometers);
|
||||
if (m_battery_capacity == 52000) {
|
||||
Bat_cell_capacity = 78.0 * 2 * (StandardMetrics.ms_v_bat_soh->AsFloat() / 100.0);
|
||||
}
|
||||
if (m_battery_capacity == 41000) {
|
||||
Bat_cell_capacity = 65.6 * 2 * (StandardMetrics.ms_v_bat_soh->AsFloat() / 100.0);
|
||||
}
|
||||
if (m_battery_capacity == 22000) {
|
||||
Bat_cell_capacity = 36.0 * 2 * (StandardMetrics.ms_v_bat_soh->AsFloat() / 100.0);
|
||||
}
|
||||
ESP_LOGI(TAG, "Renault Zoe Ph2 (CAN) reload configuration: Range ideal: %d, Battery capacity: %d, Use BMS as energy counter: %s", m_range_ideal, m_battery_capacity, m_UseBMScalculation ? "yes" : "no");
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::ZoeWakeUp() {
|
||||
ESP_LOGI(TAG,"Zoe woke up (CAN Bus activity detected)");
|
||||
mt_bus_awake->SetValue(true);;
|
||||
StandardMetrics.ms_v_env_charging12v->SetValue(true);
|
||||
POLLSTATE_ON;
|
||||
ESP_LOGI(TAG, "Pollstate switched to ON");
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming CAN-frames on bus 1, connected to M-CAN
|
||||
*/
|
||||
void OvmsVehicleRenaultZoePh2CAN::IncomingFrameCan1(CAN_frame_t* p_frame) {
|
||||
//uint8_t *data = p_frame->data.u8;
|
||||
//ESP_LOGI(TAG, "M-CAN: PID:%x DATA: %02x %02x %02x %02x %02x %02x %02x %02x", p_frame->MsgID, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
|
||||
//tooooooo many packets, OVMS will crash with logging
|
||||
|
||||
//If a CAN message comes in, start polling
|
||||
if (!mt_bus_awake->AsBool()) {
|
||||
ZoeWakeUp();
|
||||
}
|
||||
//Reset CAN1 inactivity timer, inactivity after 5 sec detected to stop polling
|
||||
m_can1_activity_timer = 5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming CAN-frames on bus 2, connected to EXT-CAN
|
||||
*/
|
||||
void OvmsVehicleRenaultZoePh2CAN::IncomingFrameCan2(CAN_frame_t* p_frame) {
|
||||
//uint8_t *data = p_frame->data.u8;
|
||||
//ESP_LOGI(TAG, "V1-CAN: PID:%x DATA: %02x %02x %02x %02x %02x %02x %02x %02x", p_frame->MsgID, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
|
||||
//tooooooo many packets, OVMS will crash with logging
|
||||
|
||||
//ToDo: Analyse PIDs and copy data to useful metrics
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming CAN-frames on bus 3, connected to V1-CAN
|
||||
*/
|
||||
void OvmsVehicleRenaultZoePh2CAN::IncomingFrameCan3(CAN_frame_t* p_frame) {
|
||||
//uint8_t *data = p_frame->data.u8;
|
||||
//ESP_LOGI(TAG, "V1-CAN: PID:%x DATA: %02x %02x %02x %02x %02x %02x %02x %02x", p_frame->MsgID, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
|
||||
//tooooooo many packets, OVMS will crash with logging
|
||||
|
||||
//ToDo: Analyse PIDs and copy data to useful metrics
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming poll results
|
||||
*/
|
||||
void OvmsVehicleRenaultZoePh2CAN::IncomingPollReply(canbus* bus, uint16_t type, uint16_t pid, uint8_t* data, uint8_t length, uint16_t remain) {
|
||||
string& rxbuf = zoe_can1_rxbuf;
|
||||
|
||||
//ESP_LOGV(TAG, "pid: %04x length: %d m_poll_ml_remain: %d m_poll_ml_frame: %d", pid, length, m_poll_ml_remain, m_poll_ml_frame);
|
||||
|
||||
// init / fill rx buffer:
|
||||
if (m_poll_ml_frame == 0) {
|
||||
rxbuf.clear();
|
||||
rxbuf.reserve(length + remain);
|
||||
}
|
||||
rxbuf.append((char*)data, length);
|
||||
|
||||
if (remain)
|
||||
return;
|
||||
|
||||
switch (m_poll_moduleid_low) {
|
||||
// ****** INV *****
|
||||
case 0x18daf1df:
|
||||
IncomingINV(type, pid, rxbuf.data(), rxbuf.size());
|
||||
break;
|
||||
// ****** EVC *****
|
||||
case 0x18daf1da:
|
||||
IncomingEVC(type, pid, rxbuf.data(), rxbuf.size());
|
||||
break;
|
||||
// ****** BCM *****
|
||||
case 0x765:
|
||||
IncomingBCM(type, pid, rxbuf.data(), rxbuf.size());
|
||||
break;
|
||||
// ****** LBC *****
|
||||
case 0x18daf1db:
|
||||
IncomingLBC(type, pid, rxbuf.data(), rxbuf.size());
|
||||
break;
|
||||
// ****** HVAC *****
|
||||
case 0x764:
|
||||
IncomingHVAC(type, pid, rxbuf.data(), rxbuf.size());
|
||||
break;
|
||||
// ****** UCM *****
|
||||
case 0x76D:
|
||||
IncomingUCM(type, pid, rxbuf.data(), rxbuf.size());
|
||||
break;
|
||||
// ****** CLUSTER *****
|
||||
//case 0x763:
|
||||
// IncomingCLUSTER(type, pid, rxbuf.data(), rxbuf.size());
|
||||
// break;
|
||||
}
|
||||
}
|
||||
|
||||
int OvmsVehicleRenaultZoePh2CAN::calcMinutesRemaining(float charge_voltage, float charge_current) {
|
||||
float bat_soc = StandardMetrics.ms_v_bat_soc->AsFloat(100);
|
||||
|
||||
float remaining_wh = m_battery_capacity - (m_battery_capacity * bat_soc / 100.0);
|
||||
float remaining_hours = remaining_wh / (charge_current * charge_voltage);
|
||||
float remaining_mins = remaining_hours * 60.0;
|
||||
//ESP_LOGD(TAG, "SOC: %f, BattCap:%d, Current: %f, Voltage: %f, RemainWH: %f, RemainHour: %f, RemainMin: %f", bat_soc, m_battery_capacity, charge_current, charge_voltage, remaining_wh, remaining_hours, remaining_mins);
|
||||
return MIN( 1440, (int)remaining_mins );
|
||||
}
|
||||
|
||||
//Handle Charging values
|
||||
void OvmsVehicleRenaultZoePh2CAN::ChargeStatistics() {
|
||||
float charge_current = fabs(StandardMetrics.ms_v_bat_current->AsFloat(0, Amps));
|
||||
float charge_voltage = StandardMetrics.ms_v_bat_voltage->AsFloat(0, Volts);
|
||||
float battery_power = fabs(StandardMetrics.ms_v_bat_power->AsFloat(0, kW));
|
||||
float charger_power = StandardMetrics.ms_v_charge_power->AsFloat(0, kW);
|
||||
float ac_current = StandardMetrics.ms_v_charge_current->AsFloat(0, Amps);
|
||||
string ac_phases = mt_main_phases->AsString();
|
||||
|
||||
if (CarIsCharging != CarLastCharging) {
|
||||
if (CarIsCharging) {
|
||||
StandardMetrics.ms_v_charge_kwh->SetValue(0);
|
||||
StandardMetrics.ms_v_charge_inprogress->SetValue(CarIsCharging);
|
||||
if (m_UseBMScalculation) {
|
||||
mt_bat_chg_start->SetValue(StandardMetrics.ms_v_charge_kwh_grid_total->AsFloat());
|
||||
}
|
||||
} else {
|
||||
StandardMetrics.ms_v_charge_inprogress->SetValue(CarIsCharging);
|
||||
}
|
||||
}
|
||||
CarLastCharging = CarIsCharging;
|
||||
|
||||
if (!StandardMetrics.ms_v_charge_pilot->AsBool() || !StandardMetrics.ms_v_charge_inprogress->AsBool() || (charge_current <= 0.0) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (charge_voltage > 0 && charge_current > 0) {
|
||||
float power = charge_voltage * charge_current / 1000.0;
|
||||
float energy = power / 3600.0 * 10.0;
|
||||
float c_efficiency;
|
||||
|
||||
if (m_UseBMScalculation) {
|
||||
StandardMetrics.ms_v_charge_kwh->SetValue(StandardMetrics.ms_v_charge_kwh_grid_total->AsFloat() - mt_bat_chg_start->AsFloat());
|
||||
} else {
|
||||
StandardMetrics.ms_v_charge_kwh->SetValue( StandardMetrics.ms_v_charge_kwh->AsFloat() + energy);
|
||||
}
|
||||
|
||||
int minsremaining = calcMinutesRemaining(charge_voltage, charge_current);
|
||||
StandardMetrics.ms_v_charge_duration_full->SetValue(minsremaining, Minutes);
|
||||
|
||||
if (StandardMetrics.ms_v_charge_type->AsString() == "type2") {
|
||||
c_efficiency = (battery_power / charger_power) * 100.0;
|
||||
if (c_efficiency < 100.0) {
|
||||
StandardMetrics.ms_v_charge_efficiency->SetValue(c_efficiency);
|
||||
}
|
||||
ESP_LOGI(TAG, "Charge time remaining: %d mins, AC Charge at %.2f kW with %.1f amps, %s at %.1f efficiency, %.2f powerfactor", minsremaining, charger_power, ac_current, ac_phases.c_str(), StandardMetrics.ms_v_charge_efficiency->AsFloat(100), ACInputPowerFactor);
|
||||
} else if (StandardMetrics.ms_v_charge_type->AsString() == "ccs" || StandardMetrics.ms_v_charge_type->AsString() == "chademo") {
|
||||
StandardMetrics.ms_v_charge_power->SetValue(battery_power);
|
||||
ESP_LOGI(TAG, "Charge time remaining: %d mins, DC Charge at %.2f kW", minsremaining, battery_power);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::EnergyStatisticsOVMS() {
|
||||
float voltage = StandardMetrics.ms_v_bat_voltage->AsFloat(0, Volts);
|
||||
float current = StandardMetrics.ms_v_bat_current->AsFloat(0, Amps);
|
||||
|
||||
float power = voltage * current / 1000.0;
|
||||
|
||||
if (power != 0.0 && StandardMetrics.ms_v_env_on->AsBool()) {
|
||||
float energy = power / 3600.0 * 10.0;
|
||||
if (energy > 0.0f)
|
||||
StandardMetrics.ms_v_bat_energy_used->SetValue( StandardMetrics.ms_v_bat_energy_used->AsFloat() + energy);
|
||||
else
|
||||
StandardMetrics.ms_v_bat_energy_recd->SetValue( StandardMetrics.ms_v_bat_energy_recd->AsFloat() - energy);
|
||||
}
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::EnergyStatisticsBMS() {
|
||||
StandardMetrics.ms_v_bat_energy_used->SetValue(StandardMetrics.ms_v_bat_energy_used_total->AsFloat() - mt_bat_used_start->AsFloat());
|
||||
StandardMetrics.ms_v_bat_energy_recd->SetValue(StandardMetrics.ms_v_bat_energy_recd_total->AsFloat() - mt_bat_recd_start->AsFloat());
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::Ticker10(uint32_t ticker) {
|
||||
if (StandardMetrics.ms_v_charge_pilot->AsBool() && !StandardMetrics.ms_v_env_on->AsBool()) {
|
||||
ChargeStatistics();
|
||||
} else {
|
||||
if (m_UseBMScalculation) {
|
||||
EnergyStatisticsBMS();
|
||||
} else {
|
||||
EnergyStatisticsOVMS();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2CAN::Ticker1(uint32_t ticker) {
|
||||
//Stop polling after 5 seconds of inactivity on CAN1 (M-CAN)
|
||||
if (m_can1_activity_timer > 0) {
|
||||
if (--m_can1_activity_timer == 0) {
|
||||
ESP_LOGI(TAG,"Zoe has gone to sleep (No messages on M-CAN for 10 seconds)");
|
||||
mt_bus_awake->SetValue(false);
|
||||
StandardMetrics.ms_v_env_awake->SetValue(false);
|
||||
StandardMetrics.ms_v_env_charging12v->SetValue(false);
|
||||
StandardMetrics.ms_v_pos_speed->SetValue( 0 );
|
||||
StandardMetrics.ms_v_bat_12v_current->SetValue( 0 );
|
||||
StandardMetrics.ms_v_charge_12v_current->SetValue( 0 );
|
||||
StandardMetrics.ms_v_bat_current->SetValue( 0 );
|
||||
POLLSTATE_OFF;
|
||||
ESP_LOGI(TAG, "Pollstate switched to OFF");
|
||||
//Check if car is locked, if not send notify
|
||||
if (!StandardMetrics.ms_v_env_locked->AsBool()) {
|
||||
MyNotify.NotifyString("alert", "vehicle.lock", "Vehicle is not locked");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (StandardMetrics.ms_v_env_on->AsBool() && !CarIsDriving) {
|
||||
CarIsDriving = true;
|
||||
//Start trip after power on
|
||||
StandardMetrics.ms_v_pos_trip->SetValue(0);
|
||||
mt_pos_odometer_start->SetValue(StandardMetrics.ms_v_pos_odometer->AsFloat(0));
|
||||
StandardMetrics.ms_v_bat_energy_used->SetValue(0);
|
||||
StandardMetrics.ms_v_bat_energy_recd->SetValue(0);
|
||||
if (m_UseBMScalculation) {
|
||||
mt_bat_used_start->SetValue(StandardMetrics.ms_v_bat_energy_used_total->AsFloat());
|
||||
mt_bat_recd_start->SetValue(StandardMetrics.ms_v_bat_energy_recd_total->AsFloat());
|
||||
}
|
||||
}
|
||||
if (CarIsDriving && !CarIsDrivingInit) {
|
||||
CarIsDrivingInit = true;
|
||||
ESP_LOGI(TAG, "Pollstate switched to DRIVING");
|
||||
POLLSTATE_DRIVING;
|
||||
}
|
||||
if (!StandardMetrics.ms_v_env_on->AsBool() && CarIsDriving) {
|
||||
CarIsDriving = false;
|
||||
CarIsDrivingInit = false;
|
||||
ESP_LOGI(TAG, "Pollstate switched to ON");
|
||||
POLLSTATE_ON;
|
||||
}
|
||||
if (StandardMetrics.ms_v_charge_pilot->AsBool() && StandardMetrics.ms_v_charge_inprogress->AsBool() && !CarIsCharging) {
|
||||
CarIsCharging = true;
|
||||
ESP_LOGI(TAG, "Pollstate switched to CHARGING");
|
||||
POLLSTATE_CHARGING;
|
||||
} else if (!StandardMetrics.ms_v_charge_pilot->AsBool() && CarIsCharging) {
|
||||
CarIsCharging = false;
|
||||
StandardMetrics.ms_v_charge_duration_full->SetValue(0);
|
||||
ESP_LOGI(TAG, "Pollstate switched to ON");
|
||||
POLLSTATE_ON;
|
||||
} else if (StandardMetrics.ms_v_charge_pilot->AsBool() && CarIsCharging && StandardMetrics.ms_v_charge_substate->AsString() == "powerwait") {
|
||||
CarIsCharging = false;
|
||||
StandardMetrics.ms_v_charge_duration_full->SetValue(0);
|
||||
ESP_LOGI(TAG, "Pollstate switched to OFF, Wait for power...");
|
||||
POLLSTATE_OFF;
|
||||
} else if (StandardMetrics.ms_v_charge_pilot->AsBool() && CarIsCharging && StandardMetrics.ms_v_charge_state->AsString() == "done") {
|
||||
CarIsCharging = false;
|
||||
StandardMetrics.ms_v_charge_duration_full->SetValue(0);
|
||||
ESP_LOGI(TAG, "Pollstate switched to OFF, done charging...");
|
||||
POLLSTATE_OFF;
|
||||
}
|
||||
|
||||
if (StandardMetrics.ms_v_env_on->AsBool()) {
|
||||
StandardMetrics.ms_v_pos_trip->SetValue(StandardMetrics.ms_v_pos_odometer->AsFloat(0) - mt_pos_odometer_start->AsFloat(0));
|
||||
}
|
||||
StandardMetrics.ms_v_bat_range_est->SetValue((m_range_ideal * (StandardMetrics.ms_v_bat_soc->AsFloat(1) * 0.01)), Kilometers);
|
||||
|
||||
}
|
||||
|
||||
OvmsVehicleRenaultZoePh2CAN* OvmsVehicleRenaultZoePh2CAN::GetInstance(OvmsWriter* writer /*=NULL*/)
|
||||
{
|
||||
OvmsVehicleRenaultZoePh2CAN* zoe_ph2_can = (OvmsVehicleRenaultZoePh2CAN*) MyVehicleFactory.ActiveVehicle();
|
||||
string type = StdMetrics.ms_v_type->AsString();
|
||||
if (!zoe_ph2_can || type != "RZ2C") {
|
||||
if (writer)
|
||||
writer->puts("Error: Renault Zoe Ph2 (CAN) vehicle module not selected");
|
||||
return NULL;
|
||||
}
|
||||
return zoe_ph2_can;
|
||||
}
|
||||
|
||||
class OvmsVehicleRenaultZoePh2CANInit {
|
||||
public: OvmsVehicleRenaultZoePh2CANInit();
|
||||
} MyOvmsVehicleRenaultZoePh2CANInit __attribute__ ((init_priority (9000)));
|
||||
|
||||
|
||||
OvmsVehicleRenaultZoePh2CANInit::OvmsVehicleRenaultZoePh2CANInit()
|
||||
{
|
||||
ESP_LOGI(TAG, "Registering Vehicle: Renault Zoe Ph2 (CAN) (9000)");
|
||||
MyVehicleFactory.RegisterVehicle<OvmsVehicleRenaultZoePh2CAN>("RZ2C","Renault Zoe Ph2 (CAN)");
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
; Project: Open Vehicle Monitor System
|
||||
; Date: 19th Nov 2022
|
||||
;
|
||||
; (C) 2022 Carsten Schmiemann
|
||||
;
|
||||
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
; of this software and associated documentation files (the "Software"), to deal
|
||||
; in the Software without restriction, including without limitation the rights
|
||||
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
; copies of the Software, and to permit persons to whom the Software is
|
||||
; furnished to do so, subject to the following conditions:
|
||||
;
|
||||
; The above copyright notice and this permission notice shall be included in
|
||||
; all copies or substantial portions of the Software.
|
||||
;
|
||||
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
#ifndef __VEHICLE_RENAULTZOE_PH2_OBD_H__
|
||||
#define __VEHICLE_RENAULTZOE_PH2_OBD_H__
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "can.h"
|
||||
#include "vehicle.h"
|
||||
|
||||
#include "ovms_log.h"
|
||||
#include "ovms_config.h"
|
||||
#include "ovms_metrics.h"
|
||||
#include "ovms_command.h"
|
||||
#include "freertos/timers.h"
|
||||
#ifdef CONFIG_OVMS_COMP_WEBSERVER
|
||||
#include "ovms_webserver.h"
|
||||
#endif
|
||||
|
||||
// CAN buffer access macros: b=byte# 0..7 / n=nibble# 0..15
|
||||
#define CAN_BYTE(b) data[b]
|
||||
#define CAN_UINT(b) (((UINT)CAN_BYTE(b) << 8) | CAN_BYTE(b+1))
|
||||
#define CAN_UINT24(b) (((uint32_t)CAN_BYTE(b) << 16) | ((UINT)CAN_BYTE(b+1) << 8) | CAN_BYTE(b+2))
|
||||
#define CAN_UINT32(b) (((uint32_t)CAN_BYTE(b) << 24) | ((uint32_t)CAN_BYTE(b+1) << 16) | ((UINT)CAN_BYTE(b+2) << 8) | CAN_BYTE(b+3))
|
||||
#define CAN_NIBL(b) (data[b] & 0x0f)
|
||||
#define CAN_NIBH(b) (data[b] >> 4)
|
||||
#define CAN_NIB(n) (((n)&1) ? CAN_NIBL((n)>>1) : CAN_NIBH((n)>>1))
|
||||
|
||||
#define POLLSTATE_OFF PollSetState(0);
|
||||
#define POLLSTATE_ON PollSetState(1);
|
||||
#define POLLSTATE_DRIVING PollSetState(2);
|
||||
#define POLLSTATE_CHARGING PollSetState(3);
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define TAG (OvmsVehicleRenaultZoePh2CAN::s_tag)
|
||||
|
||||
class OvmsVehicleRenaultZoePh2CAN : public OvmsVehicle {
|
||||
public:
|
||||
static const char *s_tag;
|
||||
|
||||
public:
|
||||
OvmsVehicleRenaultZoePh2CAN();
|
||||
~OvmsVehicleRenaultZoePh2CAN();
|
||||
static void WebCfgCommon(PageEntry_t& p, PageContext_t& c);
|
||||
void ConfigChanged(OvmsConfigParam* param);
|
||||
void ZoeWakeUp();
|
||||
void IncomingFrameCan1(CAN_frame_t* p_frame);
|
||||
void IncomingFrameCan2(CAN_frame_t* p_frame);
|
||||
void IncomingFrameCan3(CAN_frame_t* p_frame);
|
||||
void IncomingPollReply(canbus* bus, uint16_t type, uint16_t pid, uint8_t* data, uint8_t length, uint16_t remain);
|
||||
void WebInit();
|
||||
void WebDeInit();
|
||||
bool CarIsCharging = false;
|
||||
bool CarPluggedIn = false;
|
||||
bool CarLastCharging = false;
|
||||
bool CarIsDriving = false;
|
||||
bool CarIsDrivingInit = false;
|
||||
float ACInputPowerFactor = 0.0;
|
||||
float Bat_cell_capacity = 0.0;
|
||||
|
||||
protected:
|
||||
int m_range_ideal;
|
||||
int m_battery_capacity;
|
||||
bool m_UseCarTrip = false;
|
||||
bool m_UseBMScalculation = false;
|
||||
char zoe_vin[18] = "";
|
||||
void IncomingINV(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
void IncomingEVC(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
void IncomingBCM(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
void IncomingLBC(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
void IncomingHVAC(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
void IncomingUCM(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
//void IncomingCLUSTER(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
int calcMinutesRemaining(float charge_voltage, float charge_current);
|
||||
void ChargeStatistics();
|
||||
void EnergyStatisticsOVMS();
|
||||
void EnergyStatisticsBMS();
|
||||
virtual void Ticker10(uint32_t ticker);//Handle charge, energy statistics
|
||||
virtual void Ticker1(uint32_t ticker); //Handle trip counter
|
||||
|
||||
private:
|
||||
unsigned int m_can1_activity_timer;
|
||||
|
||||
// Renault ZOE specific metrics
|
||||
OvmsMetricBool *mt_bus_awake; //CAN bus awake status
|
||||
OvmsMetricFloat *mt_pos_odometer_start; //ODOmeter at trip start
|
||||
OvmsMetricFloat *mt_bat_used_start; //Used battery kWh at trip start
|
||||
OvmsMetricFloat *mt_bat_recd_start; //Recd battery kWh at trip start
|
||||
OvmsMetricFloat *mt_bat_chg_start; //Charge battery kWh at charge start
|
||||
OvmsMetricFloat *mt_bat_available_energy; //Available energy in battery
|
||||
OvmsMetricFloat *mt_bat_aux_power_consumer; //Power usage by consumer
|
||||
OvmsMetricFloat *mt_bat_aux_power_ptc; //Power usage by PTCs
|
||||
OvmsMetricFloat *mt_bat_max_charge_power; //Battery max allowed charge, recd power
|
||||
OvmsMetricFloat *mt_bat_cycles; //Battery full charge cycles
|
||||
OvmsMetricFloat *mt_main_power_available; //Mains power available
|
||||
OvmsMetricString *mt_main_phases; //Mains phases used
|
||||
OvmsMetricFloat *mt_main_phases_num; //Mains phases used
|
||||
OvmsMetricString *mt_inv_status; //Inverter status string
|
||||
OvmsMetricFloat *mt_inv_hv_voltage; //Inverter battery voltage sense, used for motor power calc
|
||||
OvmsMetricFloat *mt_inv_hv_current; //Inverter battery current sense, used for motor power calc
|
||||
OvmsMetricFloat *mt_mot_temp_stator1; //Temp of motor stator 1
|
||||
OvmsMetricFloat *mt_mot_temp_stator2; //Temp of motor stator 2
|
||||
OvmsMetricFloat *mt_hvac_compressor_speed; //Compressor speed
|
||||
OvmsMetricFloat *mt_hvac_compressor_pressure;//Compressor high-side pressure in BAR
|
||||
OvmsMetricFloat *mt_hvac_compressor_power; //Compressor power usage
|
||||
OvmsMetricString *mt_hvac_compressor_mode; //Compressor mode
|
||||
OvmsMetricFloat *mt_v_env_pressure; //Ambient air pressure
|
||||
|
||||
//CAN Commands section
|
||||
|
||||
public:
|
||||
static OvmsVehicleRenaultZoePh2CAN* GetInstance(OvmsWriter* writer=NULL);
|
||||
void CanInit();
|
||||
int CanRequest(uint16_t txid, uint16_t rxid, string request, string& response, int timeout_ms);
|
||||
static void shell_can_request(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv);
|
||||
virtual vehicle_command_t CommandPreHeat(bool climatecontrolon);
|
||||
virtual vehicle_command_t CommandWakeup();
|
||||
virtual vehicle_command_t CommandLock(const char* pin);
|
||||
virtual vehicle_command_t CommandUnlock(const char* pin);
|
||||
|
||||
protected:
|
||||
OvmsCommand *cmd_zoe_ph2;
|
||||
string zoe_can1_rxbuf;
|
||||
OvmsSemaphore zoe_can1_rxwait;
|
||||
uint16_t zoe_can1_rxerr;
|
||||
OvmsMutex zoe_can1_request;
|
||||
};
|
||||
|
||||
#endif //#ifndef __VEHICLE_RENAULTZOE_PH2_OBD_H__
|
14
OVMS.V3/components/vehicle_renaultzoe_ph2_obd/component.mk
Normal file
14
OVMS.V3/components/vehicle_renaultzoe_ph2_obd/component.mk
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
||||
|
||||
ifdef CONFIG_OVMS_VEHICLE_RENAULTZOE_PH2_OBD
|
||||
COMPONENT_ADD_INCLUDEDIRS:=src
|
||||
COMPONENT_SRCDIRS:=src
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
endif
|
49
OVMS.V3/components/vehicle_renaultzoe_ph2_obd/docs/index.rst
Normal file
49
OVMS.V3/components/vehicle_renaultzoe_ph2_obd/docs/index.rst
Normal file
|
@ -0,0 +1,49 @@
|
|||
==============================
|
||||
Renault Zoe Phase 2 (OBD port)
|
||||
==============================
|
||||
|
||||
Vehicle Type: **RZ2O**
|
||||
|
||||
This vehicle type supports the Renault Zoe(PH2) through OBD connection.
|
||||
All values are read-only, no control possible because of CAN Gateway.
|
||||
|
||||
----------------
|
||||
Support Overview
|
||||
----------------
|
||||
|
||||
=========================== ==============
|
||||
Function Support Status
|
||||
=========================== ==============
|
||||
Hardware OVMS v3.3
|
||||
Vehicle Cable OBD-II to DB9 Data Cable for OVMS (Generic OBD2 Cable (left))
|
||||
GSM Antenna 1000500 Open Vehicles OVMS GSM Antenna (or any compatible antenna)
|
||||
GPS Antenna 1020200 Universal GPS Antenna (SMA Connector) (or any compatible antenna)
|
||||
SOC Display Yes
|
||||
Range Display Yes
|
||||
GPS Location Yes (from modem module GPS)
|
||||
Speed Display Yes
|
||||
Temperature Display Yes (Battery, Outside, Cabin, Motor, Inverter, Tyres)
|
||||
BMS v+t Display Yes
|
||||
TPMS Display Zoe Yes (Pressure and temperature)
|
||||
Charge Status Display Yes
|
||||
Charge Interruption Alerts Yes
|
||||
Charge Control No (planned, but access to CAN after gw neccessary)
|
||||
Cabin Pre-heat/cool Control No (planned, but access to CAN after gw neccessary)
|
||||
Lock/Unlock Vehicle Yes (display only)
|
||||
Valet Mode Control No
|
||||
=========================== ==============
|
||||
|
||||
Others:
|
||||
|
||||
=================================== ==============
|
||||
Door open/close Yes (exclude hood)
|
||||
Battery full charge cycles Yes
|
||||
Battery max charge, recd pwr Yes
|
||||
Trip counter from Car No (was included, but datapoint is extremly unreliable)
|
||||
Battery lifetime gauges Yes (Charged, Recd and Used kWh)
|
||||
Heat pump power, rpm and hp press. Yes
|
||||
Aux power gauges Yes (testing needed)
|
||||
Charge type Yes (DC charge, testing needed)
|
||||
Headlights Status Yes (lowbeam)
|
||||
Charge efficiency calculation Yes (but only for AC, pf is measured with power analyzer and included as statics)
|
||||
=================================== ==============
|
|
@ -23,48 +23,64 @@
|
|||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "vehicle_renaultzoe_ph2.h"
|
||||
#include "vehicle_renaultzoe_ph2_obd.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::IncomingBCM(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
void OvmsVehicleRenaultZoePh2OBD::IncomingBCM(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x4204: { // TPMS pressure - front left
|
||||
StandardMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_FL, (float)CAN_UINT(0) * 7.5 / 10, kPa);
|
||||
//ESP_LOGD(TAG, "4204 BCM tpms pressure FL: %f", CAN_UINT(0) * 7.5);
|
||||
case 0x6300: { // TPMS pressure - front left
|
||||
if ((CAN_UINT(0) * 7.5) < 7672) {
|
||||
StandardMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_FL, (float)CAN_UINT(0) * 7.5 / 10, kPa);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6300 BCM tpms pressure FL: %f", CAN_UINT(0) * 7.5);
|
||||
break;
|
||||
}
|
||||
case 0x4205: { // TPMS pressure - front right
|
||||
StandardMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_FR, (float)CAN_UINT(0) * 7.5 / 10, kPa);
|
||||
//ESP_LOGD(TAG, "4205 BCM tpms pressure FR: %f", CAN_UINT(0) * 7.5);
|
||||
case 0x6301: { // TPMS pressure - front right
|
||||
if ((CAN_UINT(0) * 7.5) < 7672) {
|
||||
StandardMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_FR, (float)CAN_UINT(0) * 7.5 / 10, kPa);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6301 BCM tpms pressure FR: %f", CAN_UINT(0) * 7.5);
|
||||
break;
|
||||
}
|
||||
case 0x4206: { // TPMS pressure - rear left
|
||||
StandardMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_RL, (float)CAN_UINT(0) * 7.5 / 10, kPa);
|
||||
//ESP_LOGD(TAG, "4206 BCM tpms pressure RL: %f", CAN_UINT(0) * 7.5);
|
||||
case 0x6302: { // TPMS pressure - rear left
|
||||
if ((CAN_UINT(0) * 7.5) < 7672) {
|
||||
StandardMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_RL, (float)CAN_UINT(0) * 7.5 / 10, kPa);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6302 BCM tpms pressure RL: %f", CAN_UINT(0) * 7.5);
|
||||
break;
|
||||
}
|
||||
case 0x4207: { // TPMS pressure - rear right
|
||||
StandardMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_RR, (float)CAN_UINT(0) * 7.5 / 10, kPa);
|
||||
//ESP_LOGD(TAG, "4207 BCM tpms pressure RR: %f", CAN_UINT(0) * 7.5);
|
||||
case 0x6303: { // TPMS pressure - rear right
|
||||
if ((CAN_UINT(0) * 7.5) < 7672) {
|
||||
StandardMetrics.ms_v_tpms_pressure->SetElemValue(MS_V_TPMS_IDX_RR, (float)CAN_UINT(0) * 7.5 / 10, kPa);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6303 BCM tpms pressure RR: %f", CAN_UINT(0) * 7.5);
|
||||
break;
|
||||
}
|
||||
case 0x420C: { // TPMS temp - front left
|
||||
StandardMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_FL, (float)(CAN_UINT(0) - 30) * 0.001, Celcius);
|
||||
//ESP_LOGD(TAG, "420C BCM tpms temp FL: %f", (CAN_UINT(0) - 30) * 0.001);
|
||||
case 0x6310: { // TPMS temp - front left
|
||||
if (CAN_BYTE(0) < 127) {
|
||||
StandardMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_FL, CAN_BYTE(0) - 30, Celcius);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6310 BCM tpms temp FL: %d", CAN_NIB(0));
|
||||
break;
|
||||
}
|
||||
case 0x420D: { // TPMS temp - front right
|
||||
StandardMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_FR, (float)(CAN_UINT(0) - 30) * 0.001, Celcius);
|
||||
//ESP_LOGD(TAG, "420D BCM tpms temp FR: %f", (CAN_UINT(0) - 30) * 0.001);
|
||||
case 0x6311: { // TPMS temp - front right
|
||||
if (CAN_BYTE(0) < 127) {
|
||||
StandardMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_FR, CAN_BYTE(0) - 30, Celcius);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6311 BCM tpms temp FR: %d", CAN_NIBL(0));
|
||||
break;
|
||||
}
|
||||
case 0x420E: { // TPMS temp - rear left
|
||||
StandardMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_RL, (float)(CAN_UINT(0) - 30) * 0.001, Celcius);
|
||||
//ESP_LOGD(TAG, "420E BCM tpms temp RL: %f", (CAN_UINT(0) - 30) * 0.001);
|
||||
case 0x6312: { // TPMS temp - rear left
|
||||
if (CAN_BYTE(0) < 127) {
|
||||
StandardMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_RL, CAN_BYTE(0) - 30, Celcius);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6312 BCM tpms temp RL: %d", CAN_NIBH(0));
|
||||
break;
|
||||
}
|
||||
case 0x420F: { // TPMS temp - rear right
|
||||
StandardMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_RR, (float)(CAN_UINT(0) - 30) * 0.001, Celcius);
|
||||
//ESP_LOGD(TAG, "420F BCM tpms temp RR: %f", (CAN_UINT(0) - 30) * 0.001);
|
||||
case 0x6313: { // TPMS temp - rear right
|
||||
if (CAN_BYTE(0) < 127) {
|
||||
StandardMetrics.ms_v_tpms_temp->SetElemValue(MS_V_TPMS_IDX_RR, CAN_BYTE(0) - 30, Celcius);
|
||||
}
|
||||
//ESP_LOGD(TAG, "6313 BCM tpms temp RR: %d", CAN_BYTE(0));
|
||||
break;
|
||||
}
|
||||
case 0x4109: { // TPMS alert - front left
|
||||
|
@ -149,6 +165,49 @@ void OvmsVehicleRenaultZoePh2::IncomingBCM(uint16_t type, uint16_t pid, const ch
|
|||
//ESP_LOGD(TAG, "609B Tailgate: %d", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x4186: { //Low beam lights
|
||||
StandardMetrics.ms_v_env_headlights->SetValue((bool)CAN_UINT(0));
|
||||
/*if ((bool)CAN_UINT(0)) {
|
||||
ESP_LOGD(TAG, "4186 Low beam lights: active");
|
||||
} else {
|
||||
ESP_LOGD(TAG, "4186 Low beam lights: inactive");
|
||||
}*/
|
||||
break;
|
||||
}
|
||||
case 0x60C6: { //Ignition relay (switch)
|
||||
/*if ((bool)CAN_UINT(0)) {
|
||||
ESP_LOGD(TAG, "60C6 Ignition relay: active");
|
||||
} else {
|
||||
ESP_LOGD(TAG, "60C6 Ignition relay: inactive");
|
||||
}*/
|
||||
if (!CarIsCharging) { //Igniton while charging
|
||||
StandardMetrics.ms_v_env_on->SetValue((bool)CAN_UINT(0));
|
||||
StandardMetrics.ms_v_env_awake->SetValue((bool)CAN_UINT(0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x4060: { //Vehicle identificaftion number
|
||||
zoe_vin[0] = CAN_BYTE(0);
|
||||
zoe_vin[1] = CAN_BYTE(1);
|
||||
zoe_vin[2] = CAN_BYTE(2);
|
||||
zoe_vin[3] = CAN_BYTE(3);
|
||||
zoe_vin[4] = CAN_BYTE(4);
|
||||
zoe_vin[5] = CAN_BYTE(5);
|
||||
zoe_vin[6] = CAN_BYTE(6);
|
||||
zoe_vin[7] = CAN_BYTE(7);
|
||||
zoe_vin[8] = CAN_BYTE(8);
|
||||
zoe_vin[9] = CAN_BYTE(9);
|
||||
zoe_vin[10] = CAN_BYTE(10);
|
||||
zoe_vin[11] = CAN_BYTE(11);
|
||||
zoe_vin[12] = CAN_BYTE(12);
|
||||
zoe_vin[13] = CAN_BYTE(13);
|
||||
zoe_vin[14] = CAN_BYTE(14);
|
||||
zoe_vin[15] = CAN_BYTE(15);
|
||||
zoe_vin[16] = CAN_BYTE(16);
|
||||
zoe_vin[17] = 0;
|
||||
StandardMetrics.ms_v_vin->SetValue((string) zoe_vin);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
char *buf = NULL;
|
|
@ -23,9 +23,9 @@
|
|||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "vehicle_renaultzoe_ph2.h"
|
||||
#include "vehicle_renaultzoe_ph2_obd.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::IncomingEVC(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
void OvmsVehicleRenaultZoePh2OBD::IncomingEVC(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x2006: { //Odometer (Total Vehicle Distance)
|
||||
StandardMetrics.ms_v_pos_odometer->SetValue((float) CAN_UINT24(0), Kilometers);
|
||||
|
@ -42,29 +42,20 @@ void OvmsVehicleRenaultZoePh2::IncomingEVC(uint16_t type, uint16_t pid, const ch
|
|||
//ESP_LOGD(TAG, "2005 EVC ms_v_charge_12v_voltage: %f", CAN_UINT(0) * 0.01);
|
||||
break;
|
||||
}
|
||||
case 0x21CF: { //Inverter status --- Main switch for polling and driving state
|
||||
case 0x21CF: { //Inverter status
|
||||
//ESP_LOGD(TAG, "21CF EVC mt_inv_status: %d", CAN_NIBL(0));
|
||||
if (CAN_NIBL(0) == 1) {
|
||||
mt_inv_status->SetValue("Inverter off");
|
||||
StandardMetrics.ms_v_env_on->SetValue(false);
|
||||
StandardMetrics.ms_v_env_awake->SetValue(false);
|
||||
|
||||
} else if (CAN_NIBL(0) == 2) {
|
||||
mt_inv_status->SetValue("Inverter on");
|
||||
StandardMetrics.ms_v_env_on->SetValue(true);
|
||||
StandardMetrics.ms_v_env_awake->SetValue(true);
|
||||
StandardMetrics.ms_v_door_chargeport->SetValue(false);
|
||||
} else if (CAN_NIBL(0) == 3) {
|
||||
mt_inv_status->SetValue("Inverter decharging");
|
||||
StandardMetrics.ms_v_env_on->SetValue(false);
|
||||
StandardMetrics.ms_v_env_awake->SetValue(false);
|
||||
} else if (CAN_NIBL(0) == 4) {
|
||||
mt_inv_status->SetValue("Inverter alternator mode");
|
||||
StandardMetrics.ms_v_env_on->SetValue(false);
|
||||
StandardMetrics.ms_v_env_awake->SetValue(false);
|
||||
} else if (CAN_NIBL(0) == 5) {
|
||||
mt_inv_status->SetValue("Inverter ready to sleep");
|
||||
StandardMetrics.ms_v_env_on->SetValue(false);
|
||||
StandardMetrics.ms_v_env_awake->SetValue(false);
|
||||
} else {
|
||||
mt_inv_status->SetValue("Inverter state unknown");
|
||||
}
|
||||
|
@ -76,12 +67,12 @@ void OvmsVehicleRenaultZoePh2::IncomingEVC(uint16_t type, uint16_t pid, const ch
|
|||
break;
|
||||
}
|
||||
case 0x2A09: { // Power consumption by consumer
|
||||
//mt_bat_aux_power_consumer->SetValue((float) CAN_UINT(0) * 10, Watts);
|
||||
mt_bat_aux_power_consumer->SetValue((float) CAN_UINT(0) * 10, Watts);
|
||||
//ESP_LOGD(TAG, "2A09 EVC mt_bat_aux_power_consumer: %d", CAN_UINT(0) * 10);
|
||||
break;
|
||||
}
|
||||
case 0x2191: { // Power consumption by ptc
|
||||
//mt_bat_aux_power_ptc->SetValue((float) CAN_UINT(0) * 10, Watts);
|
||||
mt_bat_aux_power_ptc->SetValue((float) CAN_UINT(0) * 10, Watts);
|
||||
//ESP_LOGD(TAG, "2191 EVC mt_bat_aux_power_ptc: %d", CAN_UINT(0) * 10);
|
||||
break;
|
||||
}
|
||||
|
@ -144,6 +135,7 @@ void OvmsVehicleRenaultZoePh2::IncomingEVC(uint16_t type, uint16_t pid, const ch
|
|||
if (CAN_NIBL(0) == 6) {
|
||||
StandardMetrics.ms_v_door_chargeport->SetValue(true);
|
||||
//ESP_LOGD(TAG, "2B6D Charge MMI States : Chargeport opened");
|
||||
ESP_LOGI(TAG, "Chargedoor opened");
|
||||
}
|
||||
if (CAN_NIBL(0) == 8) {
|
||||
StandardMetrics.ms_v_charge_state->SetValue("prepare");
|
||||
|
@ -217,7 +209,6 @@ void OvmsVehicleRenaultZoePh2::IncomingEVC(uint16_t type, uint16_t pid, const ch
|
|||
ACInputPowerFactor = 0.775;
|
||||
} else if (StandardMetrics.ms_v_charge_current->AsFloat() < 6.0f && StandardMetrics.ms_v_charge_inprogress->AsBool(false)) {
|
||||
ACInputPowerFactor = 0.05;
|
||||
ESP_LOGE(TAG, "Warning charge current too low, charging not possible");
|
||||
}
|
||||
if (StandardMetrics.ms_v_charge_type->AsString() == "type2" && mt_main_phases_num->AsFloat() == 3 && StandardMetrics.ms_v_charge_inprogress->AsBool(false)) {
|
||||
StandardMetrics.ms_v_charge_power->SetValue((StandardMetrics.ms_v_charge_current->AsFloat() * StandardMetrics.ms_v_charge_voltage->AsFloat() * ACInputPowerFactor * 1.732f) * 0.001, kW);
|
||||
|
@ -254,16 +245,6 @@ void OvmsVehicleRenaultZoePh2::IncomingEVC(uint16_t type, uint16_t pid, const ch
|
|||
//ESP_LOGD(TAG, "2B8A EVC ms_v_charge_voltage: %f", (CAN_UINT(0) * 0.5));
|
||||
break;
|
||||
}
|
||||
case 0x2009: { // Ambient air pressure
|
||||
mt_v_env_pressure->SetValue((float) (CAN_UINT(0)));
|
||||
//ESP_LOGD(TAG, "2009 EVC mt_v_env_pressure: %d mbar", CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
case 0x21CD: { // User SOC
|
||||
mt_bat_user_soc->SetValue((float) (CAN_UINT(0)), Percentage);
|
||||
//ESP_LOGD(TAG, "21CD EVC mt_bat_user_soc: %f", (float) CAN_UINT(0));
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
char *buf = NULL;
|
|
@ -22,9 +22,9 @@
|
|||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
#include "vehicle_renaultzoe_ph2.h"
|
||||
#include "vehicle_renaultzoe_ph2_obd.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::IncomingHVAC(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
void OvmsVehicleRenaultZoePh2OBD::IncomingHVAC(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x4009: { //Cabin temperature
|
||||
StandardMetrics.ms_v_env_cabintemp->SetValue(float((CAN_UINT(0) - 400) / 10), Celcius);
|
|
@ -23,9 +23,9 @@
|
|||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "vehicle_renaultzoe_ph2.h"
|
||||
#include "vehicle_renaultzoe_ph2_obd.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::IncomingINV(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
void OvmsVehicleRenaultZoePh2OBD::IncomingINV(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x700C: { // Inverter temperature
|
||||
StandardMetrics.ms_v_inv_temp->SetValue(float((CAN_UINT24(0) * 0.001953125) - 40), Celcius);
|
||||
|
@ -44,11 +44,6 @@ void OvmsVehicleRenaultZoePh2::IncomingINV(uint16_t type, uint16_t pid, const ch
|
|||
//ESP_LOGD(TAG, "7010 INV mt_mot_temp_stator2: %f", float((CAN_UINT24(0) * 0.001953125) - 40));
|
||||
break;
|
||||
}
|
||||
//case 0x2001: { // Motor rpm
|
||||
// StandardMetrics.ms_v_mot_rpm->SetValue(float(CAN_UINT24(0) / 2) - 16000);
|
||||
// ESP_LOGD(TAG, "2001 INV ms_v_mot_rpm: %f", float(CAN_UINT24(0) / 2) - 16000);
|
||||
// break;
|
||||
//}
|
||||
case 0x2004: { // Battery voltage sense
|
||||
mt_inv_hv_voltage->SetValue(float(CAN_UINT(0) * 0.03125), Volts);
|
||||
//ESP_LOGD(TAG, "2004 INV mt_inv_hv_voltage: %f", float(CAN_UINT(0) * 0.03125));
|
|
@ -23,9 +23,9 @@
|
|||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "vehicle_renaultzoe_ph2.h"
|
||||
#include "vehicle_renaultzoe_ph2_obd.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::IncomingLBC(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
void OvmsVehicleRenaultZoePh2OBD::IncomingLBC(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x9005: { //Battery voltage
|
||||
StandardMetrics.ms_v_bat_voltage->SetValue((float) (CAN_UINT(0) * 0.1), Volts);
|
||||
|
@ -45,9 +45,9 @@ void OvmsVehicleRenaultZoePh2::IncomingLBC(uint16_t type, uint16_t pid, const ch
|
|||
break;
|
||||
}
|
||||
case 0x9002: { //Battery SOC
|
||||
mt_bat_lbc_soc->SetValue((float) (CAN_UINT(0)) * 0.01, Percentage);
|
||||
StandardMetrics.ms_v_bat_soc->SetValue((float) (CAN_UINT(0)) * 0.01, Percentage);
|
||||
StandardMetrics.ms_v_bat_cac->SetValue(Bat_cell_capacity * CAN_UINT(0) * 0.0001);
|
||||
//ESP_LOGD(TAG, "9002 LBC mt_bat_lbc_soc: %f", CAN_UINT(0) * 0.01);
|
||||
//ESP_LOGD(TAG, "9002 LBC mt_bat_lbc_soc: %f", bat_soc);
|
||||
break;
|
||||
}
|
||||
case 0x9003: { //Battery SOH
|
|
@ -22,9 +22,9 @@
|
|||
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
; THE SOFTWARE.
|
||||
*/
|
||||
#include "vehicle_renaultzoe_ph2.h"
|
||||
#include "vehicle_renaultzoe_ph2_obd.h"
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::IncomingUCM(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
void OvmsVehicleRenaultZoePh2OBD::IncomingUCM(uint16_t type, uint16_t pid, const char* data, uint16_t len) {
|
||||
switch (pid) {
|
||||
case 0x6079: { //12V Battery Current
|
||||
StandardMetrics.ms_v_charge_12v_current->SetValue((float) (CAN_UINT(0) * 0.1), Amps);
|
|
@ -51,7 +51,7 @@ static const OvmsVehicle::poll_pid_t renault_zoe_polls[] = {
|
|||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2218, { 0, 20, 20, 20 }, 0, ISOTP_EXTFRAME }, // Ambient air temperature
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2A09, { 0, 10, 10, 10 }, 0, ISOTP_EXTFRAME }, // Power usage by consumer
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2191, { 0, 10, 10, 10 }, 0, ISOTP_EXTFRAME }, // Power usage by ptc
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2B85, { 0, 2, 300, 10 }, 0, ISOTP_EXTFRAME }, // Charge plug preset
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2B85, { 0, 2, 300, 10 }, 0, ISOTP_EXTFRAME }, // Charge plug present
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2B6D, { 0, 2, 300, 10 }, 0, ISOTP_EXTFRAME }, // Charge MMI states
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2B7A, { 0, 2, 300, 10 }, 0, ISOTP_EXTFRAME }, // Charge type
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x3064, { 0, 10, 3, 10 }, 0, ISOTP_EXTFRAME }, // Motor rpm
|
||||
|
@ -59,19 +59,17 @@ static const OvmsVehicle::poll_pid_t renault_zoe_polls[] = {
|
|||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x300D, { 0, 10, 300, 3 }, 0, ISOTP_EXTFRAME }, // AC mains current
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x300B, { 0, 2, 300, 10 }, 0, ISOTP_EXTFRAME }, // AC phases
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2B8A, { 0, 2, 300, 10 }, 0, ISOTP_EXTFRAME }, // AC mains voltage
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2009, { 0, 20, 20, 20 }, 0, ISOTP_EXTFRAME }, // Ambient air pressure
|
||||
{ 0x18dadaf1, 0x18daf1da, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x21CD, { 0, 10, 10, 10 }, 0, ISOTP_EXTFRAME }, // User SOC
|
||||
|
||||
//BCM
|
||||
//{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIISESSION, SESSION_DEFAULT, { 0, 60, 60, 60 }, 0, ISOTP_STD }, // OBD Extended Diagnostic Session
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4204, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS pressure - front left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4205, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS pressure - front right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4206, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS pressure - rear left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4207, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS pressure - rear right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x420C, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS temp - front left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x420D, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS temp - front right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x420E, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS temp - rear left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x420F, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS temp - rear right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6300, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS pressure - front left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6301, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS pressure - front right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6302, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS pressure - rear left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6303, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS pressure - rear right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6310, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS temp - front left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6311, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS temp - front right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6312, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS temp - rear left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6313, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS temp - rear right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4109, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS alert - front left
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x410A, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS alert - front right
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x410B, { 0, 300, 300, 300 }, 0, ISOTP_STD }, // TPMS alert - rear left
|
||||
|
@ -82,6 +80,9 @@ static const OvmsVehicle::poll_pid_t renault_zoe_polls[] = {
|
|||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x61B2, { 0, 3, 3, 3 }, 0, ISOTP_STD }, // Rear left door
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x61B3, { 0, 3, 3, 3 }, 0, ISOTP_STD }, // Rear right door
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x609B, { 0, 3, 3, 3 }, 0, ISOTP_STD }, // Tailgate
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4186, { 0, 3, 3, 3 }, 0, ISOTP_STD }, // Low beam lights
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x60C6, { 0, 3, 6, 60 }, 0, ISOTP_STD }, // Ignition relay (switch), working but behavior on CHARING testing needed
|
||||
{ 0x745, 0x765, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x4060, { 0, 600, 0, 0 }, 0, ISOTP_STD }, // Vehicle identificaftion number
|
||||
|
||||
//LBC
|
||||
//{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIISESSION, SESSION_DEFAULT, { 0, 60, 60, 60 }, 0, ISOTP_EXTFRAME }, // OBD Extended Diagnostic Session
|
||||
|
@ -97,114 +98,114 @@ static const OvmsVehicle::poll_pid_t renault_zoe_polls[] = {
|
|||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9210, { 0, 60, 60, 60 }, 0, ISOTP_EXTFRAME }, // Number of complete cycles
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9018, { 0, 10, 60, 10 }, 0, ISOTP_EXTFRAME }, // Max Charge Power
|
||||
//LBC Cell voltages and temperatures, OBD Grouppoll not working
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9131, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 1
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9132, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 2
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9133, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 3
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9134, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 4
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9135, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 5
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9136, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 6
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9137, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 7
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9138, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 8
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9139, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 9
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x913A, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 10
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x913B, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 11
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x913C, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 12
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9021, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 1
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9022, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 2
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9023, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 3
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9024, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 4
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9025, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 5
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9026, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 6
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9027, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 7
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9028, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 8
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9029, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 9
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902A, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 10
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902B, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 11
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902C, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 12
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902D, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 13
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902E, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 14
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902F, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 15
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9030, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 16
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9031, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 17
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9032, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 18
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9033, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 19
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9034, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 20
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9035, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 21
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9036, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 22
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9037, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 23
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9038, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 24
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9039, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 25
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903A, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 26
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903B, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 27
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903C, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 28
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903D, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 29
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903E, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 30
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903F, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 31
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9041, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 32
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9042, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 33
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9043, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 34
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9044, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 35
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9045, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 36
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9046, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 37
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9047, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 38
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9048, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 39
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9049, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 40
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904A, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 41
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904B, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 42
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904C, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 43
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904D, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 44
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904E, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 45
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904F, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 46
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9050, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 47
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9051, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 48
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9052, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 49
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9053, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 50
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9054, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 51
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9055, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 52
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9056, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 53
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9057, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 54
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9058, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 55
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9059, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 56
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905A, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 57
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905B, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 58
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905C, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 59
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905D, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 60
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905E, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 61
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905F, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 62
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9061, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 63
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9062, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 64
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9063, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 65
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9064, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 66
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9065, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 67
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9066, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 68
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9067, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 69
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9068, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 70
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9069, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 71
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906A, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 72
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906B, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 73
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906C, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 74
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906D, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 75
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906E, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 76
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906F, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 77
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9070, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 78
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9071, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 79
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9072, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 80
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9073, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 81
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9074, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 82
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9075, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 83
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9076, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 84
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9077, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 85
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9078, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 86
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9079, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 87
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907A, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 88
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907B, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 89
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907C, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 90
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907D, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 91
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907E, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 92
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907F, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 93
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9081, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 94
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9082, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 95
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9083, { 0, 60, 600, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 96
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9131, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 1
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9132, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 2
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9133, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 3
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9134, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 4
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9135, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 5
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9136, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 6
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9137, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 7
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9138, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 8
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9139, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 9
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x913A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 10
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x913B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 11
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x913C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Pack temperature 12
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9021, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 1
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9022, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 2
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9023, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 3
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9024, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 4
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9025, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 5
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9026, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 6
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9027, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 7
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9028, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 8
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9029, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 9
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 10
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 11
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 12
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902D, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 13
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902E, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 14
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x902F, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 15
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9030, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 16
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9031, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 17
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9032, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 18
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9033, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 19
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9034, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 20
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9035, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 21
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9036, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 22
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9037, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 23
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9038, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 24
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9039, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 25
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 26
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 27
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 28
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903D, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 29
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903E, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 30
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x903F, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 31
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9041, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 32
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9042, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 33
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9043, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 34
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9044, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 35
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9045, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 36
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9046, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 37
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9047, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 38
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9048, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 39
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9049, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 40
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 41
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 42
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 43
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904D, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 44
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904E, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 45
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x904F, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 46
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9050, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 47
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9051, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 48
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9052, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 49
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9053, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 50
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9054, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 51
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9055, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 52
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9056, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 53
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9057, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 54
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9058, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 55
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9059, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 56
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 57
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 58
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 59
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905D, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 60
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905E, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 61
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x905F, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 62
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9061, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 63
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9062, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 64
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9063, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 65
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9064, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 66
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9065, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 67
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9066, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 68
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9067, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 69
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9068, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 70
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9069, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 71
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 72
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 73
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 74
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906D, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 75
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906E, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 76
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x906F, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 77
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9070, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 78
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9071, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 79
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9072, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 80
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9073, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 81
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9074, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 82
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9075, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 83
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9076, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 84
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9077, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 85
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9078, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 86
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9079, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 87
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907A, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 88
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907B, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 89
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907C, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 90
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907D, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 91
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907E, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 92
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x907F, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 93
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9081, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 94
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9082, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 95
|
||||
{ 0x18dadbf1, 0x18daf1db, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x9083, { 0, 60, 300, 60 }, 0, ISOTP_EXTFRAME }, // Cell voltage 96
|
||||
|
||||
//HVAC
|
||||
//{ 0x744, 0x764, VEHICLE_POLL_TYPE_OBDIISESSION, SESSION_EXTDIAG, { 0, 60, 60, 60 }, 0, ISOTP_STD }, // OBD Extended Diagnostic Session
|
||||
|
@ -219,8 +220,5 @@ static const OvmsVehicle::poll_pid_t renault_zoe_polls[] = {
|
|||
//{ 0x74D, 0x76D, VEHICLE_POLL_TYPE_OBDIISESSION, SESSION_AfterSales, { 0, 60, 60, 60 }, 0, ISOTP_STD }, // OBD Extended Diagnostic Session
|
||||
{ 0x74D, 0x76D, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x6079, { 0, 10, 10, 10 }, 0, ISOTP_STD }, // 12V Battery current
|
||||
|
||||
//TDB
|
||||
//{ 0x743, 0x763, VEHICLE_POLL_TYPE_OBDIISESSION, SESSION_AfterSales, { 0, 60, 60, 60 }, 0, ISOTP_STD }, // OBD Extended Diagnostic Session
|
||||
{ 0x743, 0x763, VEHICLE_POLL_TYPE_OBDIIEXTENDED, 0x2101, { 0, 30, 10, 300 }, 0, ISOTP_STD }, // Cluster - trip counter
|
||||
POLL_LIST_END
|
||||
};
|
|
@ -36,24 +36,22 @@
|
|||
#include "ovms_notify.h"
|
||||
#include "ovms_webserver.h"
|
||||
|
||||
#include "vehicle_renaultzoe_ph2.h"
|
||||
#include "vehicle_renaultzoe_ph2_obd.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define _attr(text) (c.encode_html(text).c_str())
|
||||
#define _html(text) (c.encode_html(text).c_str())
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::WebCfgCommon(PageEntry_t& p, PageContext_t& c)
|
||||
void OvmsVehicleRenaultZoePh2OBD::WebCfgCommon(PageEntry_t& p, PageContext_t& c)
|
||||
{
|
||||
std::string error, rangeideal, battcapacity;
|
||||
bool UseCarTrip, UseBMScalculation, UseBMSsoc;
|
||||
bool UseBMScalculation;
|
||||
|
||||
if (c.method == "POST") {
|
||||
rangeideal = c.getvar("rangeideal");
|
||||
battcapacity = c.getvar("battcapacity");
|
||||
UseCarTrip = (c.getvar("UseCarTrip") == "no");
|
||||
UseBMScalculation = (c.getvar("UseBMScalculation") == "no");
|
||||
UseBMSsoc = (c.getvar("UseBMSsoc") == "no");
|
||||
|
||||
if (!rangeideal.empty()) {
|
||||
int v = atoi(rangeideal.c_str());
|
||||
|
@ -62,11 +60,9 @@ void OvmsVehicleRenaultZoePh2::WebCfgCommon(PageEntry_t& p, PageContext_t& c)
|
|||
}
|
||||
if (error == "") {
|
||||
// store:
|
||||
MyConfig.SetParamValue("xrz2", "rangeideal", rangeideal);
|
||||
MyConfig.SetParamValue("xrz2", "battcapacity", battcapacity);
|
||||
MyConfig.SetParamValueBool("xrz2", "UseCarTrip", UseCarTrip);
|
||||
MyConfig.SetParamValueBool("xrz2", "UseBMScalculation", UseBMScalculation);
|
||||
MyConfig.SetParamValueBool("xrz2", "UseBMSsoc", UseBMSsoc);
|
||||
MyConfig.SetParamValue("xrz2o", "rangeideal", rangeideal);
|
||||
MyConfig.SetParamValue("xrz2o", "battcapacity", battcapacity);
|
||||
MyConfig.SetParamValueBool("xrz2o", "UseBMScalculation", UseBMScalculation);
|
||||
|
||||
c.head(200);
|
||||
c.alert("success", "<p class=\"lead\">Renault Zoe Ph2 battery setup saved.</p>");
|
||||
|
@ -81,11 +77,9 @@ void OvmsVehicleRenaultZoePh2::WebCfgCommon(PageEntry_t& p, PageContext_t& c)
|
|||
}
|
||||
else {
|
||||
// read configuration:
|
||||
rangeideal = MyConfig.GetParamValue("xrz2", "rangeideal", "350");
|
||||
battcapacity = MyConfig.GetParamValue("xrz2", "battcapacity", "52000");
|
||||
UseCarTrip = MyConfig.GetParamValueBool("xrz2", "UseCarTrip", false);
|
||||
UseBMScalculation = MyConfig.GetParamValueBool("xrz2", "UseBMScalculation", false);
|
||||
UseBMSsoc = MyConfig.GetParamValueBool("xrz2", "UseBMSsoc", false);
|
||||
rangeideal = MyConfig.GetParamValue("xrz2o", "rangeideal", "350");
|
||||
battcapacity = MyConfig.GetParamValue("xrz2o", "battcapacity", "52000");
|
||||
UseBMScalculation = MyConfig.GetParamValueBool("xrz2o", "UseBMScalculation", false);
|
||||
c.head(200);
|
||||
}
|
||||
|
||||
|
@ -102,15 +96,7 @@ void OvmsVehicleRenaultZoePh2::WebCfgCommon(PageEntry_t& p, PageContext_t& c)
|
|||
|
||||
c.input_slider("Range Ideal", "rangeideal", 3, "km", -1, atoi(rangeideal.c_str()), 350, 80, 500, 1,
|
||||
"<p>Default 350km. Ideal Range...</p>");
|
||||
|
||||
c.fieldset_start("Trip counter settings");
|
||||
c.input_radio_start("Which tripcounter to use?", "UseCarTrip");
|
||||
c.input_radio_option("UseCarTrip", "Internal (New trip everytime car starts)", "yes", UseCarTrip == false);
|
||||
c.input_radio_option("UseCarTrip", "Car trip counter from Cluster", "no", UseCarTrip == true);
|
||||
c.input_radio_end("");
|
||||
|
||||
c.fieldset_end();
|
||||
|
||||
|
||||
c.fieldset_start("Battery energy calculation");
|
||||
|
||||
c.input_radio_start("Which energy calculation?", "UseBMScalculation");
|
||||
|
@ -118,11 +104,6 @@ void OvmsVehicleRenaultZoePh2::WebCfgCommon(PageEntry_t& p, PageContext_t& c)
|
|||
c.input_radio_option("UseBMScalculation", "BMS-based calculation", "no", UseBMScalculation == true);
|
||||
c.input_radio_end("");
|
||||
|
||||
c.input_radio_start("State of Charge - Display", "UseBMSsoc");
|
||||
c.input_radio_option("UseBMSsoc", "User SOC from EVC", "yes", UseBMSsoc == false);
|
||||
c.input_radio_option("UseBMSsoc", "Real SOC from BMS", "no", UseBMSsoc == true);
|
||||
c.input_radio_end("");
|
||||
|
||||
c.fieldset_end();
|
||||
|
||||
c.print("<hr>");
|
||||
|
@ -135,19 +116,19 @@ void OvmsVehicleRenaultZoePh2::WebCfgCommon(PageEntry_t& p, PageContext_t& c)
|
|||
/**
|
||||
* WebInit: register pages
|
||||
*/
|
||||
void OvmsVehicleRenaultZoePh2::WebInit()
|
||||
void OvmsVehicleRenaultZoePh2OBD::WebInit()
|
||||
{
|
||||
MyWebServer.RegisterPage("/xrz2/battmon", "BMS View", OvmsWebServer::HandleBmsCellMonitor, PageMenu_Vehicle, PageAuth_Cookie);
|
||||
MyWebServer.RegisterPage("/xrz2/settings", "Setup", WebCfgCommon, PageMenu_Vehicle, PageAuth_Cookie);
|
||||
MyWebServer.RegisterPage("/xrz2o/battmon", "BMS View", OvmsWebServer::HandleBmsCellMonitor, PageMenu_Vehicle, PageAuth_Cookie);
|
||||
MyWebServer.RegisterPage("/xrz2o/settings", "Setup", WebCfgCommon, PageMenu_Vehicle, PageAuth_Cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* WebDeInit: deregister pages
|
||||
*/
|
||||
void OvmsVehicleRenaultZoePh2::WebDeInit()
|
||||
void OvmsVehicleRenaultZoePh2OBD::WebDeInit()
|
||||
{
|
||||
MyWebServer.DeregisterPage("/xrz2/battmon");
|
||||
MyWebServer.DeregisterPage("/xrz2/battery");
|
||||
MyWebServer.DeregisterPage("/xrz2o/battmon");
|
||||
MyWebServer.DeregisterPage("/xrz2o/battery");
|
||||
}
|
||||
|
||||
|
|
@ -39,11 +39,13 @@
|
|||
#include "ovms_peripherals.h"
|
||||
#include "ovms_netmanager.h"
|
||||
|
||||
#include "vehicle_renaultzoe_ph2.h"
|
||||
#include "vehicle_renaultzoe_ph2_obd.h"
|
||||
#include "ph2_poller.h"
|
||||
|
||||
OvmsVehicleRenaultZoePh2::OvmsVehicleRenaultZoePh2() {
|
||||
ESP_LOGI(TAG, "Start Renault Zoe Ph2 vehicle module");
|
||||
const char *OvmsVehicleRenaultZoePh2OBD::s_tag = "v-zoe-ph2-obd";
|
||||
|
||||
OvmsVehicleRenaultZoePh2OBD::OvmsVehicleRenaultZoePh2OBD() {
|
||||
ESP_LOGI(TAG, "Start Renault Zoe Ph2 (OBD) vehicle module");
|
||||
|
||||
//Init variables supressing push on boot up
|
||||
StandardMetrics.ms_v_type->SetValue("RZ2");
|
||||
|
@ -53,7 +55,7 @@ OvmsVehicleRenaultZoePh2::OvmsVehicleRenaultZoePh2() {
|
|||
StandardMetrics.ms_v_charge_substate->SetValue("stopped");
|
||||
StandardMetrics.ms_v_env_on->SetValue(false);
|
||||
|
||||
MyConfig.RegisterParam("xrz2", "Renault Zoe Ph2 configuration", true, true);
|
||||
MyConfig.RegisterParam("xrz2o", "Renault Zoe Ph2 (OBD) configuration", true, true);
|
||||
ConfigChanged(NULL);
|
||||
|
||||
// Init Zoe Ph2 OBD Connection (CAN Gateway)
|
||||
|
@ -68,31 +70,27 @@ OvmsVehicleRenaultZoePh2::OvmsVehicleRenaultZoePh2() {
|
|||
|
||||
// Renault ZOE specific metrics
|
||||
mt_bus_awake = MyMetrics.InitBool("zph2.v.bus.awake", SM_STALE_NONE, false);
|
||||
mt_pos_odometer_start = MyMetrics.InitFloat("zph2.v.pos.odometer.start", SM_STALE_MID, 0, Kilometers);
|
||||
mt_pos_car_trip = MyMetrics.InitFloat("zph2.v.pos.car.trip", SM_STALE_NONE, 0, Kilometers);
|
||||
mt_bat_used_start = MyMetrics.InitFloat("zph2.b.used.start", SM_STALE_MID, 0, kWh);
|
||||
mt_bat_recd_start = MyMetrics.InitFloat("zph2.b.recd.start", SM_STALE_MID, 0, kWh);
|
||||
mt_bat_chg_start = MyMetrics.InitFloat("zph2.b.chg.start", SM_STALE_MID, 0, kWh);
|
||||
mt_bat_available_energy = MyMetrics.InitFloat("zph2.b.avail.energy", SM_STALE_NONE, 0, kWh);
|
||||
mt_pos_odometer_start = MyMetrics.InitFloat("zph2.v.pos.odometer.start", SM_STALE_MID, 0, Kilometers, true);
|
||||
mt_bat_used_start = MyMetrics.InitFloat("zph2.b.used.start", SM_STALE_MID, 0, kWh, true);
|
||||
mt_bat_recd_start = MyMetrics.InitFloat("zph2.b.recd.start", SM_STALE_MID, 0, kWh, true);
|
||||
mt_bat_chg_start = MyMetrics.InitFloat("zph2.b.chg.start", SM_STALE_MID, 0, kWh, true);
|
||||
mt_bat_available_energy = MyMetrics.InitFloat("zph2.b.avail.energy", SM_STALE_NONE, 0, kWh, true);
|
||||
mt_bat_aux_power_consumer = MyMetrics.InitFloat("zph2.b.aux.power.consumer", SM_STALE_MID, 0, Watts);
|
||||
mt_bat_aux_power_ptc = MyMetrics.InitFloat("zph2.b.aux.power.ptc", SM_STALE_MID, 0, Watts);
|
||||
mt_bat_max_charge_power = MyMetrics.InitFloat("zph2.b.max.charge.power", SM_STALE_MID, 0, kW);
|
||||
mt_bat_max_charge_power = MyMetrics.InitFloat("zph2.b.max.charge.power", SM_STALE_MID, 0, kW, true);
|
||||
mt_bat_cycles = MyMetrics.InitFloat("zph2.b.cycles", SM_STALE_MID, 0, Other, true);
|
||||
mt_main_power_available = MyMetrics.InitFloat("zph2.c.main.power.available", SM_STALE_MIN, 0, kW);
|
||||
mt_main_phases = MyMetrics.InitString("zph2.c.main.phases", SM_STALE_MIN, 0);
|
||||
mt_main_phases_num = MyMetrics.InitFloat("zph2.c.main.phases.num", SM_STALE_MIN, 0);
|
||||
mt_inv_status = MyMetrics.InitString("zph2.m.inverter.status", SM_STALE_NONE, 0);
|
||||
mt_inv_hv_voltage = MyMetrics.InitFloat("zph2.i.voltage", SM_STALE_MID, 0, Volts);
|
||||
mt_inv_hv_voltage = MyMetrics.InitFloat("zph2.i.voltage", SM_STALE_MID, 0, Volts, true);
|
||||
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);
|
||||
mt_v_env_pressure = MyMetrics.InitFloat("zph2.v.e.pressure", SM_STALE_MIN, 0, mBar);
|
||||
mt_bat_lbc_soc = MyMetrics.InitFloat("zph2.b.lbc.soc", SM_STALE_MAX, 0, Percentage, true);
|
||||
mt_bat_user_soc = MyMetrics.InitFloat("zph2.b.user.soc", SM_STALE_MAX, 0, Percentage, true);
|
||||
|
||||
// BMS configuration:
|
||||
BmsSetCellArrangementVoltage(96, 1);
|
||||
|
@ -107,20 +105,18 @@ OvmsVehicleRenaultZoePh2::OvmsVehicleRenaultZoePh2() {
|
|||
#endif
|
||||
}
|
||||
|
||||
OvmsVehicleRenaultZoePh2::~OvmsVehicleRenaultZoePh2() {
|
||||
ESP_LOGI(TAG, "Stop Renault Zoe Ph2 vehicle module");
|
||||
OvmsVehicleRenaultZoePh2OBD::~OvmsVehicleRenaultZoePh2OBD() {
|
||||
ESP_LOGI(TAG, "Stop Renault Zoe Ph2 (OBD) vehicle module");
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::ConfigChanged(OvmsConfigParam* param) {
|
||||
if (param && param->GetName() != "xrz2")
|
||||
void OvmsVehicleRenaultZoePh2OBD::ConfigChanged(OvmsConfigParam* param) {
|
||||
if (param && param->GetName() != "xrz2o")
|
||||
return;
|
||||
|
||||
// get values from config store
|
||||
m_range_ideal = MyConfig.GetParamValueInt("xrz2", "rangeideal", 350);
|
||||
m_battery_capacity = MyConfig.GetParamValueInt("xrz2", "battcapacity", 52000);
|
||||
m_UseCarTrip = MyConfig.GetParamValueBool("xrz2", "UseCarTrip", false);
|
||||
m_UseBMScalculation = MyConfig.GetParamValueBool("xrz2", "UseBMScalculation", false);
|
||||
m_UseBMSsoc = MyConfig.GetParamValueBool("xrz2", "UseBMSsoc", false);
|
||||
m_range_ideal = MyConfig.GetParamValueInt("xrz2o", "rangeideal", 350);
|
||||
m_battery_capacity = MyConfig.GetParamValueInt("xrz2o", "battcapacity", 52000);
|
||||
m_UseBMScalculation = MyConfig.GetParamValueBool("xrz2o", "UseBMScalculation", false);
|
||||
StandardMetrics.ms_v_bat_range_ideal->SetValue(m_range_ideal, Kilometers);
|
||||
if (m_battery_capacity == 52000) {
|
||||
Bat_cell_capacity = 78.0 * 2 * (StandardMetrics.ms_v_bat_soh->AsFloat() / 100.0);
|
||||
|
@ -131,10 +127,10 @@ void OvmsVehicleRenaultZoePh2::ConfigChanged(OvmsConfigParam* param) {
|
|||
if (m_battery_capacity == 22000) {
|
||||
Bat_cell_capacity = 36.0 * 2 * (StandardMetrics.ms_v_bat_soh->AsFloat() / 100.0);
|
||||
}
|
||||
ESP_LOGI(TAG, "Renault Zoe Ph2 reload configuration: Range ideal: %d, Battery capacity: %d, Use Car trip counter: %s, Use BMS as energy counter: %s, Use BMS for SOC: %s", m_range_ideal, m_battery_capacity, m_UseCarTrip ? "Yes" : "No", m_UseBMScalculation ? "yes" : "no", m_UseBMSsoc ? "yes" : "no");
|
||||
ESP_LOGI(TAG, "Renault Zoe Ph2 (OBD) reload configuration: Range ideal: %d, Battery capacity: %d, Use BMS as energy counter: %s", m_range_ideal, m_battery_capacity, m_UseBMScalculation ? "yes" : "no");
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::ZoeWakeUp() {
|
||||
void OvmsVehicleRenaultZoePh2OBD::ZoeWakeUp() {
|
||||
ESP_LOGI(TAG,"Zoe woke up (CAN Bus activity detected)");
|
||||
mt_bus_awake->SetValue(true);;
|
||||
StandardMetrics.ms_v_env_charging12v->SetValue(true);
|
||||
|
@ -145,7 +141,7 @@ void OvmsVehicleRenaultZoePh2::ZoeWakeUp() {
|
|||
/**
|
||||
* Handles incoming CAN-frames on bus 1
|
||||
*/
|
||||
void OvmsVehicleRenaultZoePh2::IncomingFrameCan1(CAN_frame_t* p_frame) {
|
||||
void OvmsVehicleRenaultZoePh2OBD::IncomingFrameCan1(CAN_frame_t* p_frame) {
|
||||
uint8_t *data = p_frame->data.u8;
|
||||
//ESP_LOGI(TAG, "PID:%x DATA: %02x %02x %02x %02x %02x %02x %02x %02x", p_frame->MsgID, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
|
||||
//ESP_LOGD(TAG, "Status CAN Bus: %s", mt_bus_awake->AsBool() ? "true" : "false");
|
||||
|
@ -162,6 +158,10 @@ void OvmsVehicleRenaultZoePh2::IncomingFrameCan1(CAN_frame_t* p_frame) {
|
|||
StandardMetrics.ms_v_bat_current->SetValue( 0 );
|
||||
POLLSTATE_OFF;
|
||||
ESP_LOGI(TAG, "Pollstate switched to OFF");
|
||||
//Check if car is locked, if not send notify
|
||||
if (!StandardMetrics.ms_v_env_locked->AsBool()) {
|
||||
MyNotify.NotifyString("alert", "vehicle.lock", "Vehicle is not locked");
|
||||
}
|
||||
} else if (!mt_bus_awake->AsBool()) {
|
||||
ZoeWakeUp();
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ void OvmsVehicleRenaultZoePh2::IncomingFrameCan1(CAN_frame_t* p_frame) {
|
|||
/**
|
||||
* Handles incoming poll results
|
||||
*/
|
||||
void OvmsVehicleRenaultZoePh2::IncomingPollReply(canbus* bus, uint16_t type, uint16_t pid, uint8_t* data, uint8_t length, uint16_t remain) {
|
||||
void OvmsVehicleRenaultZoePh2OBD::IncomingPollReply(canbus* bus, uint16_t type, uint16_t pid, uint8_t* data, uint8_t length, uint16_t remain) {
|
||||
string& rxbuf = zoe_obd_rxbuf;
|
||||
|
||||
//ESP_LOGV(TAG, "pid: %04x length: %d m_poll_ml_remain: %d m_poll_ml_frame: %d", pid, length, m_poll_ml_remain, m_poll_ml_frame);
|
||||
|
@ -215,16 +215,16 @@ void OvmsVehicleRenaultZoePh2::IncomingPollReply(canbus* bus, uint16_t type, uin
|
|||
IncomingUCM(type, pid, rxbuf.data(), rxbuf.size());
|
||||
break;
|
||||
// ****** CLUSTER *****
|
||||
case 0x763:
|
||||
IncomingCLUSTER(type, pid, rxbuf.data(), rxbuf.size());
|
||||
break;
|
||||
//case 0x763:
|
||||
// IncomingCLUSTER(type, pid, rxbuf.data(), rxbuf.size());
|
||||
// break;
|
||||
}
|
||||
}
|
||||
|
||||
int OvmsVehicleRenaultZoePh2::calcMinutesRemaining(float charge_voltage, float charge_current) {
|
||||
float bat_soc = mt_bat_lbc_soc->AsFloat(100);
|
||||
int OvmsVehicleRenaultZoePh2OBD::calcMinutesRemaining(float charge_voltage, float charge_current) {
|
||||
float bat_soc = StandardMetrics.ms_v_bat_soc->AsFloat(100);
|
||||
|
||||
float remaining_wh = m_battery_capacity * bat_soc / 100.0;
|
||||
float remaining_wh = m_battery_capacity - (m_battery_capacity * bat_soc / 100.0);
|
||||
float remaining_hours = remaining_wh / (charge_current * charge_voltage);
|
||||
float remaining_mins = remaining_hours * 60.0;
|
||||
//ESP_LOGD(TAG, "SOC: %f, BattCap:%d, Current: %f, Voltage: %f, RemainWH: %f, RemainHour: %f, RemainMin: %f", bat_soc, m_battery_capacity, charge_current, charge_voltage, remaining_wh, remaining_hours, remaining_mins);
|
||||
|
@ -232,7 +232,7 @@ int OvmsVehicleRenaultZoePh2::calcMinutesRemaining(float charge_voltage, float c
|
|||
}
|
||||
|
||||
//Handle Charging values
|
||||
void OvmsVehicleRenaultZoePh2::ChargeStatistics() {
|
||||
void OvmsVehicleRenaultZoePh2OBD::ChargeStatistics() {
|
||||
float charge_current = fabs(StandardMetrics.ms_v_bat_current->AsFloat(0, Amps));
|
||||
float charge_voltage = StandardMetrics.ms_v_bat_voltage->AsFloat(0, Volts);
|
||||
float battery_power = fabs(StandardMetrics.ms_v_bat_power->AsFloat(0, kW));
|
||||
|
@ -260,6 +260,7 @@ void OvmsVehicleRenaultZoePh2::ChargeStatistics() {
|
|||
if (charge_voltage > 0 && charge_current > 0) {
|
||||
float power = charge_voltage * charge_current / 1000.0;
|
||||
float energy = power / 3600.0 * 10.0;
|
||||
float c_efficiency;
|
||||
|
||||
if (m_UseBMScalculation) {
|
||||
StandardMetrics.ms_v_charge_kwh->SetValue(StandardMetrics.ms_v_charge_kwh_grid_total->AsFloat() - mt_bat_chg_start->AsFloat());
|
||||
|
@ -271,7 +272,10 @@ void OvmsVehicleRenaultZoePh2::ChargeStatistics() {
|
|||
StandardMetrics.ms_v_charge_duration_full->SetValue(minsremaining, Minutes);
|
||||
|
||||
if (StandardMetrics.ms_v_charge_type->AsString() == "type2") {
|
||||
StandardMetrics.ms_v_charge_efficiency->SetValue((battery_power / charger_power) * 100.0);
|
||||
c_efficiency = (battery_power / charger_power) * 100.0;
|
||||
if (c_efficiency < 100.0) {
|
||||
StandardMetrics.ms_v_charge_efficiency->SetValue(c_efficiency);
|
||||
}
|
||||
ESP_LOGI(TAG, "Charge time remaining: %d mins, AC Charge at %.2f kW with %.1f amps, %s at %.1f efficiency, %.2f powerfactor", minsremaining, charger_power, ac_current, ac_phases.c_str(), StandardMetrics.ms_v_charge_efficiency->AsFloat(100), ACInputPowerFactor);
|
||||
} else if (StandardMetrics.ms_v_charge_type->AsString() == "ccs" || StandardMetrics.ms_v_charge_type->AsString() == "chademo") {
|
||||
StandardMetrics.ms_v_charge_power->SetValue(battery_power);
|
||||
|
@ -280,7 +284,7 @@ void OvmsVehicleRenaultZoePh2::ChargeStatistics() {
|
|||
}
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::EnergyStatisticsOVMS() {
|
||||
void OvmsVehicleRenaultZoePh2OBD::EnergyStatisticsOVMS() {
|
||||
float voltage = StandardMetrics.ms_v_bat_voltage->AsFloat(0, Volts);
|
||||
float current = StandardMetrics.ms_v_bat_current->AsFloat(0, Amps);
|
||||
|
||||
|
@ -295,12 +299,12 @@ void OvmsVehicleRenaultZoePh2::EnergyStatisticsOVMS() {
|
|||
}
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::EnergyStatisticsBMS() {
|
||||
void OvmsVehicleRenaultZoePh2OBD::EnergyStatisticsBMS() {
|
||||
StandardMetrics.ms_v_bat_energy_used->SetValue(StandardMetrics.ms_v_bat_energy_used_total->AsFloat() - mt_bat_used_start->AsFloat());
|
||||
StandardMetrics.ms_v_bat_energy_recd->SetValue(StandardMetrics.ms_v_bat_energy_recd_total->AsFloat() - mt_bat_recd_start->AsFloat());
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::Ticker10(uint32_t ticker) {
|
||||
void OvmsVehicleRenaultZoePh2OBD::Ticker10(uint32_t ticker) {
|
||||
if (StandardMetrics.ms_v_charge_pilot->AsBool() && !StandardMetrics.ms_v_env_on->AsBool()) {
|
||||
ChargeStatistics();
|
||||
} else {
|
||||
|
@ -312,8 +316,8 @@ void OvmsVehicleRenaultZoePh2::Ticker10(uint32_t ticker) {
|
|||
}
|
||||
}
|
||||
|
||||
void OvmsVehicleRenaultZoePh2::Ticker1(uint32_t ticker) {
|
||||
if (StandardMetrics.ms_v_env_on->AsBool() && !CarIsDriving && !m_UseCarTrip) {
|
||||
void OvmsVehicleRenaultZoePh2OBD::Ticker1(uint32_t ticker) {
|
||||
if (StandardMetrics.ms_v_env_on->AsBool() && !CarIsDriving) {
|
||||
CarIsDriving = true;
|
||||
//Start trip after power on
|
||||
StandardMetrics.ms_v_pos_trip->SetValue(0);
|
||||
|
@ -350,30 +354,27 @@ void OvmsVehicleRenaultZoePh2::Ticker1(uint32_t ticker) {
|
|||
StandardMetrics.ms_v_charge_duration_full->SetValue(0);
|
||||
ESP_LOGI(TAG, "Pollstate switched to OFF, Wait for power...");
|
||||
POLLSTATE_OFF;
|
||||
} else if (StandardMetrics.ms_v_charge_pilot->AsBool() && CarIsCharging && StandardMetrics.ms_v_charge_state->AsString() == "done") {
|
||||
CarIsCharging = false;
|
||||
StandardMetrics.ms_v_charge_duration_full->SetValue(0);
|
||||
ESP_LOGI(TAG, "Pollstate switched to OFF, done charging...");
|
||||
POLLSTATE_OFF;
|
||||
}
|
||||
|
||||
if (StandardMetrics.ms_v_env_on->AsBool() && !m_UseCarTrip) {
|
||||
if (StandardMetrics.ms_v_env_on->AsBool()) {
|
||||
StandardMetrics.ms_v_pos_trip->SetValue(StandardMetrics.ms_v_pos_odometer->AsFloat(0) - mt_pos_odometer_start->AsFloat(0));
|
||||
}
|
||||
if (m_UseCarTrip) {
|
||||
StandardMetrics.ms_v_pos_trip->SetValue(mt_pos_car_trip->AsFloat());
|
||||
}
|
||||
StandardMetrics.ms_v_bat_range_est->SetValue((m_range_ideal * (StandardMetrics.ms_v_bat_soc->AsFloat(1) * 0.01)), Kilometers);
|
||||
|
||||
if(m_UseBMSsoc) {
|
||||
StandardMetrics.ms_v_bat_soc->SetValue(mt_bat_lbc_soc->AsFloat(0));
|
||||
} else {
|
||||
StandardMetrics.ms_v_bat_soc->SetValue(mt_bat_user_soc->AsFloat(0));
|
||||
}
|
||||
}
|
||||
|
||||
class OvmsVehicleRenaultZoePh2Init {
|
||||
public: OvmsVehicleRenaultZoePh2Init();
|
||||
} MyOvmsVehicleRenaultZoePh2Init __attribute__ ((init_priority (9000)));
|
||||
class OvmsVehicleRenaultZoePh2OBDInit {
|
||||
public: OvmsVehicleRenaultZoePh2OBDInit();
|
||||
} MyOvmsVehicleRenaultZoePh2OBDInit __attribute__ ((init_priority (9000)));
|
||||
|
||||
|
||||
OvmsVehicleRenaultZoePh2Init::OvmsVehicleRenaultZoePh2Init()
|
||||
OvmsVehicleRenaultZoePh2OBDInit::OvmsVehicleRenaultZoePh2OBDInit()
|
||||
{
|
||||
ESP_LOGI(TAG, "Registering Vehicle: Renault Zoe Ph2 (9000)");
|
||||
MyVehicleFactory.RegisterVehicle<OvmsVehicleRenaultZoePh2>("RZ2","Renault Zoe Ph2");
|
||||
ESP_LOGI(TAG, "Registering Vehicle: Renault Zoe Ph2 (OBD) (9000)");
|
||||
MyVehicleFactory.RegisterVehicle<OvmsVehicleRenaultZoePh2OBD>("RZ2O","Renault Zoe Ph2 (OBD)");
|
||||
}
|
|
@ -23,10 +23,8 @@
|
|||
; THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __VEHICLE_RENAULTZOE_PH2_H__
|
||||
#define __VEHICLE_RENAULTZOE_PH2_H__
|
||||
|
||||
static const char *TAG = "v-zoe-ph2";
|
||||
#ifndef __VEHICLE_RENAULTZOE_PH2_OBD_H__
|
||||
#define __VEHICLE_RENAULTZOE_PH2_OBD_H__
|
||||
|
||||
#include <atomic>
|
||||
|
||||
|
@ -58,11 +56,15 @@ static const char *TAG = "v-zoe-ph2";
|
|||
|
||||
using namespace std;
|
||||
|
||||
class OvmsVehicleRenaultZoePh2 : public OvmsVehicle {
|
||||
#define TAG (OvmsVehicleRenaultZoePh2OBD::s_tag)
|
||||
|
||||
class OvmsVehicleRenaultZoePh2OBD : public OvmsVehicle {
|
||||
public:
|
||||
static const char *s_tag;
|
||||
|
||||
public:
|
||||
OvmsVehicleRenaultZoePh2();
|
||||
~OvmsVehicleRenaultZoePh2();
|
||||
OvmsVehicleRenaultZoePh2OBD();
|
||||
~OvmsVehicleRenaultZoePh2OBD();
|
||||
static void WebCfgCommon(PageEntry_t& p, PageContext_t& c);
|
||||
void ConfigChanged(OvmsConfigParam* param);
|
||||
void ZoeWakeUp();
|
||||
|
@ -83,14 +85,14 @@ class OvmsVehicleRenaultZoePh2 : public OvmsVehicle {
|
|||
int m_battery_capacity;
|
||||
bool m_UseCarTrip = false;
|
||||
bool m_UseBMScalculation = false;
|
||||
bool m_UseBMSsoc = false;
|
||||
char zoe_vin[18] = "";
|
||||
void IncomingINV(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
void IncomingEVC(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
void IncomingBCM(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
void IncomingLBC(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
void IncomingHVAC(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
void IncomingUCM(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
void IncomingCLUSTER(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
//void IncomingCLUSTER(uint16_t type, uint16_t pid, const char* data, uint16_t len);
|
||||
int calcMinutesRemaining(float charge_voltage, float charge_current);
|
||||
void ChargeStatistics();
|
||||
void EnergyStatisticsOVMS();
|
||||
|
@ -102,7 +104,6 @@ class OvmsVehicleRenaultZoePh2 : public OvmsVehicle {
|
|||
// Renault ZOE specific metrics
|
||||
OvmsMetricBool *mt_bus_awake; //CAN bus awake status
|
||||
OvmsMetricFloat *mt_pos_odometer_start; //ODOmeter at trip start
|
||||
OvmsMetricFloat *mt_pos_car_trip; //Cluster tripcounter
|
||||
OvmsMetricFloat *mt_bat_used_start; //Used battery kWh at trip start
|
||||
OvmsMetricFloat *mt_bat_recd_start; //Recd battery kWh at trip start
|
||||
OvmsMetricFloat *mt_bat_chg_start; //Charge battery kWh at charge start
|
||||
|
@ -111,8 +112,6 @@ class OvmsVehicleRenaultZoePh2 : public OvmsVehicle {
|
|||
OvmsMetricFloat *mt_bat_aux_power_ptc; //Power usage by PTCs
|
||||
OvmsMetricFloat *mt_bat_max_charge_power; //Battery max allowed charge, recd power
|
||||
OvmsMetricFloat *mt_bat_cycles; //Battery full charge cycles
|
||||
OvmsMetricFloat *mt_bat_lbc_soc; //Battery real SOC by BMS
|
||||
OvmsMetricFloat *mt_bat_user_soc; //Battery user SOC by Cluster
|
||||
OvmsMetricFloat *mt_main_power_available; //Mains power available
|
||||
OvmsMetricString *mt_main_phases; //Mains phases used
|
||||
OvmsMetricFloat *mt_main_phases_num; //Mains phases used
|
||||
|
@ -132,4 +131,4 @@ class OvmsVehicleRenaultZoePh2 : public OvmsVehicle {
|
|||
string zoe_obd_rxbuf;
|
||||
};
|
||||
|
||||
#endif //#ifndef __VEHICLE_RENAULTZOE_PH2_H__
|
||||
#endif //#ifndef __VEHICLE_RENAULTZOE_PH2_OBD_H__
|
|
@ -353,13 +353,20 @@ config OVMS_VEHICLE_CAN_RX_QUEUE_SIZE
|
|||
help
|
||||
The size of the CAN bus RX queue (at the vehicle component).
|
||||
|
||||
config OVMS_VEHICLE_RENAULTZOE_PH2
|
||||
bool "Include support for Renault Zoe PH2 vehicles"
|
||||
config OVMS_VEHICLE_RENAULTZOE_PH2_OBD
|
||||
bool "Include support for Renault Zoe PH2 vehicles via OBD port (read-only)"
|
||||
default y
|
||||
depends on OVMS
|
||||
help
|
||||
Enable to include support for Renault Zoe Ph2 vehicles.
|
||||
|
||||
Enable to include support for Renault Zoe Ph2 vehicles via OBD port (read-only).
|
||||
|
||||
config OVMS_VEHICLE_RENAULTZOE_PH2_CAN
|
||||
bool "Include support for Renault Zoe PH2 vehicles via direct CAN access after Core Can Gateway"
|
||||
default y
|
||||
depends on OVMS
|
||||
help
|
||||
Enable to include support for Renault Zoe Ph2 vehicles via direct CAN access after Core Can Gateway.
|
||||
|
||||
endmenu # Vehicle Support
|
||||
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ void ConsoleAsync::HandleDeviceEvent(void* pEvent)
|
|||
uart_flush(EX_UART_NUM);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "uart event type: %d", event.type);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -257,6 +257,8 @@ MetricsStandard::MetricsStandard()
|
|||
ms_v_pos_gpsmode = new OvmsMetricString(MS_V_POS_GPSMODE, SM_STALE_MIN);
|
||||
ms_v_pos_gpshdop = new OvmsMetricFloat(MS_V_POS_GPSHDOP, SM_STALE_MIN);
|
||||
ms_v_pos_satcount= new OvmsMetricInt(MS_V_POS_SATCOUNT, SM_STALE_MIN);
|
||||
ms_v_pos_gpssq = new OvmsMetricInt(MS_V_POS_GPSSQ, SM_STALE_MIN, Percentage);
|
||||
ms_v_pos_gpstime = new OvmsMetricInt(MS_V_POS_GPSTIME, SM_STALE_MIN, Seconds);
|
||||
ms_v_pos_latitude = new OvmsMetricFloat(MS_V_POS_LATITUDE, SM_STALE_MIN, Other, true);
|
||||
ms_v_pos_longitude = new OvmsMetricFloat(MS_V_POS_LONGITUDE, SM_STALE_MIN, Other, true);
|
||||
ms_v_pos_location = new OvmsMetricString(MS_V_POS_LOCATION, SM_STALE_MID);
|
||||
|
|
|
@ -230,6 +230,8 @@
|
|||
#define MS_V_POS_GPSMODE "v.p.gpsmode"
|
||||
#define MS_V_POS_GPSHDOP "v.p.gpshdop"
|
||||
#define MS_V_POS_SATCOUNT "v.p.satcount"
|
||||
#define MS_V_POS_GPSSQ "v.p.gpssq"
|
||||
#define MS_V_POS_GPSTIME "v.p.gpstime"
|
||||
#define MS_V_POS_LATITUDE "v.p.latitude"
|
||||
#define MS_V_POS_LONGITUDE "v.p.longitude"
|
||||
#define MS_V_POS_LOCATION "v.p.location"
|
||||
|
@ -491,6 +493,8 @@ class MetricsStandard
|
|||
OvmsMetricString* ms_v_pos_gpsmode; // <GPS><GLONASS>; N/A/D/E (None/Autonomous/Differential/Estimated)
|
||||
OvmsMetricFloat* ms_v_pos_gpshdop; // Horizontal dilution of precision (smaller=better)
|
||||
OvmsMetricInt* ms_v_pos_satcount;
|
||||
OvmsMetricInt* ms_v_pos_gpssq; // GPS signal quality [%] (<30 unusable, >50 good, >80 excellent)
|
||||
OvmsMetricInt* ms_v_pos_gpstime; // Time (UTC) of GPS coordinates [Seconds]
|
||||
OvmsMetricFloat* ms_v_pos_latitude;
|
||||
OvmsMetricFloat* ms_v_pos_longitude;
|
||||
OvmsMetricString* ms_v_pos_location; // Name of current location if defined
|
||||
|
|
|
@ -34,6 +34,7 @@ static const char *TAG = "boot";
|
|||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "rom/rtc.h"
|
||||
#include "rom/uart.h"
|
||||
#include "soc/rtc_cntl_reg.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_panic.h"
|
||||
|
@ -165,10 +166,18 @@ void boot_status(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc,
|
|||
writer->printf("\nLast crash: ");
|
||||
if (boot_data.crash_data.is_abort)
|
||||
{
|
||||
// Software controlled panic:
|
||||
writer->printf("abort() was called on core %d\n", boot_data.crash_data.core_id);
|
||||
if (boot_data.stack_overflow_taskname[0])
|
||||
writer->printf(" Stack overflow in task %s\n", boot_data.stack_overflow_taskname);
|
||||
else if (boot_data.curr_task[0].name[0] && !boot_data.curr_task[0].stackfree)
|
||||
writer->printf(" Pending stack overflow in task %s\n", boot_data.curr_task[0].name);
|
||||
else if (boot_data.curr_task[1].name[0] && !boot_data.curr_task[1].stackfree)
|
||||
writer->printf(" Pending stack overflow in task %s\n", boot_data.curr_task[1].name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Hardware exception:
|
||||
int exccause = boot_data.crash_data.reg[19];
|
||||
writer->printf("%s exception on core %d\n",
|
||||
(exccause < NUM_EDESCS) ? edesc[exccause] : "Unknown", boot_data.crash_data.core_id);
|
||||
|
@ -176,18 +185,29 @@ void boot_status(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc,
|
|||
for (int i=0; i<24; i++)
|
||||
writer->printf(" %s: 0x%08lx%s", sdesc[i], boot_data.crash_data.reg[i], ((i+1)%4) ? "" : "\n");
|
||||
}
|
||||
|
||||
for (int core = 0; core < portNUM_PROCESSORS; core++)
|
||||
{
|
||||
if (boot_data.curr_task[core].name[0])
|
||||
writer->printf(" Current task on core %d: %s, %u stack bytes free\n",
|
||||
core, boot_data.curr_task[core].name, boot_data.curr_task[core].stackfree);
|
||||
}
|
||||
|
||||
writer->printf(" Backtrace:\n ");
|
||||
for (int i=0; i<OVMS_BT_LEVELS && boot_data.crash_data.bt[i].pc; i++)
|
||||
writer->printf(" 0x%08lx", boot_data.crash_data.bt[i].pc);
|
||||
|
||||
if (boot_data.curr_event_name[0])
|
||||
{
|
||||
writer->printf("\n Event: %s@%s %u secs", boot_data.curr_event_name, boot_data.curr_event_handler,
|
||||
boot_data.curr_event_runtime);
|
||||
}
|
||||
|
||||
if (MyBoot.GetResetReason() == ESP_RST_TASK_WDT)
|
||||
{
|
||||
writer->printf("\n WDT tasks: %s", boot_data.wdt_tasknames);
|
||||
}
|
||||
|
||||
writer->printf("\n Version: %s\n", StdMetrics.ms_m_version->AsString("").c_str());
|
||||
writer->printf("\n Hardware: %s\n", StdMetrics.ms_m_hardware->AsString("").c_str());
|
||||
}
|
||||
|
@ -239,7 +259,7 @@ Boot::Boot()
|
|||
uint32_t adc_level = 0;
|
||||
for (int i = 0; i < 5; i++)
|
||||
adc_level += adc1_get_raw(ADC1_CHANNEL_0);
|
||||
float level_12v = adc_level / 5 / 195.7;
|
||||
float level_12v = (float) adc_level / 5 / 195.7;
|
||||
ESP_LOGI(TAG, "12V level: ~%.1fV", level_12v);
|
||||
if (level_12v > 11.0)
|
||||
ESP_LOGI(TAG, "12V level sufficient, proceeding with boot");
|
||||
|
@ -265,14 +285,12 @@ Boot::Boot()
|
|||
boot_data.boot_count++;
|
||||
ESP_LOGI(TAG, "Boot #%d reasons for CPU0=%d and CPU1=%d",boot_data.boot_count,cpu0,cpu1);
|
||||
|
||||
m_resetreason = boot_data.reset_hint;
|
||||
ESP_LOGI(TAG, "Reset reason %s (%d)", GetResetReasonName(), GetResetReason());
|
||||
|
||||
if (boot_data.soft_reset)
|
||||
{
|
||||
boot_data.crash_count_total = 0;
|
||||
boot_data.crash_count_early = 0;
|
||||
m_bootreason = BR_SoftReset;
|
||||
m_resetreason = ESP_RST_SW;
|
||||
ESP_LOGI(TAG, "Soft reset by user");
|
||||
}
|
||||
else if (boot_data.firmware_update)
|
||||
|
@ -281,6 +299,7 @@ Boot::Boot()
|
|||
boot_data.crash_count_early = 0;
|
||||
m_bootreason = BR_FirmwareUpdate;
|
||||
ESP_LOGI(TAG, "Firmware update reset");
|
||||
m_resetreason = ESP_RST_SW;
|
||||
}
|
||||
else if (!boot_data.stable_reached)
|
||||
{
|
||||
|
@ -288,24 +307,33 @@ Boot::Boot()
|
|||
boot_data.crash_count_early++;
|
||||
m_bootreason = BR_EarlyCrash;
|
||||
ESP_LOGE(TAG, "Early crash #%d detected", boot_data.crash_count_early);
|
||||
m_resetreason = boot_data.reset_hint;
|
||||
ESP_LOGI(TAG, "Reset reason %s (%d)", GetResetReasonName(), GetResetReason());
|
||||
}
|
||||
else
|
||||
{
|
||||
boot_data.crash_count_total++;
|
||||
m_bootreason = BR_Crash;
|
||||
ESP_LOGE(TAG, "Crash #%d detected", boot_data.crash_count_total);
|
||||
m_resetreason = boot_data.reset_hint;
|
||||
ESP_LOGI(TAG, "Reset reason %s (%d)", GetResetReasonName(), GetResetReason());
|
||||
}
|
||||
}
|
||||
|
||||
m_crash_count_early = boot_data.crash_count_early;
|
||||
m_stack_overflow = boot_data.stack_overflow;
|
||||
if (!m_stack_overflow)
|
||||
boot_data.stack_overflow_taskname[0] = 0;
|
||||
|
||||
boot_data.bootreason_cpu0 = cpu0;
|
||||
boot_data.bootreason_cpu1 = cpu1;
|
||||
boot_data.reset_hint = ESP_RST_UNKNOWN;
|
||||
|
||||
// reset flags:
|
||||
boot_data.soft_reset = false;
|
||||
boot_data.firmware_update = false;
|
||||
boot_data.stable_reached = false;
|
||||
boot_data.stack_overflow = false;
|
||||
|
||||
boot_data.crc = boot_data.calc_crc();
|
||||
|
||||
|
@ -351,6 +379,8 @@ const char* Boot::GetBootReasonName()
|
|||
|
||||
const char* Boot::GetResetReasonName()
|
||||
{
|
||||
if (m_stack_overflow)
|
||||
return "Stack overflow";
|
||||
return (m_resetreason >= 0 && m_resetreason < NUM_RESETREASONS)
|
||||
? resetreason_name[m_resetreason]
|
||||
: "Unknown reset reason";
|
||||
|
@ -448,6 +478,52 @@ bool Boot::IsShuttingDown()
|
|||
return m_shutting_down;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Direct UART output utils borrowed from esp32/panic.c
|
||||
*/
|
||||
static void panicPutChar(char c)
|
||||
{
|
||||
while (((READ_PERI_REG(UART_STATUS_REG(CONFIG_CONSOLE_UART_NUM)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT) >= 126) ;
|
||||
WRITE_PERI_REG(UART_FIFO_REG(CONFIG_CONSOLE_UART_NUM), c);
|
||||
}
|
||||
|
||||
static void panicPutStr(const char *c)
|
||||
{
|
||||
int x = 0;
|
||||
while (c[x] != 0)
|
||||
{
|
||||
panicPutChar(c[x]);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called by task_wdt_isr function (ISR for when TWDT times out).
|
||||
* It can be redefined in user code to handle twdt events.
|
||||
* Note: It has the same limitations as the interrupt function.
|
||||
* Do not use ESP_LOGI functions inside.
|
||||
*/
|
||||
extern "C" void esp_task_wdt_isr_user_handler(void)
|
||||
{
|
||||
panicPutStr("\r\n[OVMS] ***TWDT***\r\n");
|
||||
// Save TWDT task info:
|
||||
esp_task_wdt_get_trigger_tasknames(boot_data.wdt_tasknames, sizeof(boot_data.wdt_tasknames));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called if FreeRTOS detects a stack overflow.
|
||||
*/
|
||||
extern "C" void vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
|
||||
{
|
||||
panicPutStr("\r\n[OVMS] ***ERROR*** A stack overflow in task ");
|
||||
panicPutStr((char *)pcTaskName);
|
||||
panicPutStr(" has been detected.\r\n");
|
||||
strlcpy(boot_data.stack_overflow_taskname, (const char*)pcTaskName, sizeof(boot_data.stack_overflow_taskname));
|
||||
boot_data.stack_overflow = true;
|
||||
abort();
|
||||
}
|
||||
|
||||
void Boot::ErrorCallback(XtExcFrame *frame, int core_id, bool is_abort)
|
||||
{
|
||||
boot_data.reset_hint = ovms_reset_reason_get_hint();
|
||||
|
@ -495,8 +571,28 @@ void Boot::ErrorCallback(XtExcFrame *frame, int core_id, bool is_abort)
|
|||
boot_data.curr_event_runtime = 0;
|
||||
}
|
||||
|
||||
// Save TWDT task info:
|
||||
esp_task_wdt_get_trigger_tasknames(boot_data.wdt_tasknames, sizeof(boot_data.wdt_tasknames));
|
||||
// Save current tasks:
|
||||
panicPutStr("\r\n[OVMS] Current tasks: ");
|
||||
for (int core=0; core<portNUM_PROCESSORS; core++)
|
||||
{
|
||||
TaskHandle_t task = xTaskGetCurrentTaskHandleForCPU(core);
|
||||
if (task)
|
||||
{
|
||||
char *name = pcTaskGetTaskName(task);
|
||||
uint32_t stackfree = uxTaskGetStackHighWaterMark(task);
|
||||
if (core > 0) panicPutChar('|');
|
||||
panicPutStr(name);
|
||||
strlcpy(boot_data.curr_task[core].name, name, sizeof(boot_data.curr_task[core].name));
|
||||
boot_data.curr_task[core].stackfree = stackfree;
|
||||
if (!stackfree) boot_data.stack_overflow = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
boot_data.curr_task[core].name[0] = 0;
|
||||
boot_data.curr_task[core].stackfree = 0;
|
||||
}
|
||||
}
|
||||
panicPutStr("\r\n");
|
||||
|
||||
boot_data.crc = boot_data.calc_crc();
|
||||
}
|
||||
|
@ -514,6 +610,8 @@ void Boot::NotifyDebugCrash()
|
|||
// ,<curr_event_name>,<curr_event_handler>,<curr_event_runtime>
|
||||
// ,<wdt_tasknames>
|
||||
// ,<hardware_info>
|
||||
// ,<stack_overflow_task>
|
||||
// ,<core0_task>,<core0_stackfree>,<core1_task>,<core1_stackfree>
|
||||
|
||||
StringWriter buf;
|
||||
buf.reserve(2048);
|
||||
|
@ -557,6 +655,20 @@ void Boot::NotifyDebugCrash()
|
|||
buf.append(",");
|
||||
buf.append(mp_encode(StdMetrics.ms_m_hardware->AsString("")));
|
||||
|
||||
// Stack overflow task:
|
||||
std::string name = boot_data.stack_overflow_taskname;
|
||||
buf.append(",");
|
||||
buf.append(mp_encode(name));
|
||||
|
||||
// Current tasks:
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
name = boot_data.curr_task[i].name;
|
||||
buf.append(",");
|
||||
buf.append(mp_encode(name));
|
||||
buf.printf(",%u", boot_data.curr_task[i].stackfree);
|
||||
}
|
||||
|
||||
MyNotify.NotifyString("data", "debug.crash", buf.c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,6 +62,12 @@ typedef struct
|
|||
} bt[OVMS_BT_LEVELS];
|
||||
} crash_data_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[16];
|
||||
uint32_t stackfree;
|
||||
} task_info_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// data consistency:
|
||||
|
@ -83,6 +89,9 @@ typedef struct
|
|||
char curr_event_handler[16]; // … MyEvents.m_current_callback->m_caller
|
||||
uint16_t curr_event_runtime; // … monotonictime-MyEvents.m_current_started
|
||||
char wdt_tasknames[32]; // Pipe (|) separated list of the tasks that triggered the TWDT
|
||||
bool stack_overflow;
|
||||
char stack_overflow_taskname[16];
|
||||
task_info_t curr_task[portNUM_PROCESSORS];
|
||||
} boot_data_t;
|
||||
|
||||
extern boot_data_t boot_data;
|
||||
|
@ -128,6 +137,7 @@ class Boot
|
|||
bootreason_t m_bootreason;
|
||||
esp_reset_reason_t m_resetreason;
|
||||
unsigned int m_crash_count_early;
|
||||
bool m_stack_overflow;
|
||||
};
|
||||
|
||||
extern Boot MyBoot;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue