Merge branch 'dev' into idf4

This commit is contained in:
MichaelDvP
2022-05-07 15:31:54 +02:00
5 changed files with 101 additions and 52 deletions

View File

@@ -355,7 +355,7 @@ const DashboardData: FC = () => {
if (sc === '' || sc === '""') { if (sc === '' || sc === '""') {
return sc; return sc;
} }
if (sc.includes('"') || sc.includes(',') || sc.includes('\n') || sc.includes('\r')) { if (sc.includes('"') || sc.includes(';') || sc.includes('\n') || sc.includes('\r')) {
return '"' + sc.replace(/"/g, '""') + '"'; return '"' + sc.replace(/"/g, '""') + '"';
} }
return sc; return sc;
@@ -363,13 +363,13 @@ const DashboardData: FC = () => {
const makeCsvData = (columns: any, data: any) => { const makeCsvData = (columns: any, data: any) => {
return data.reduce((csvString: any, rowItem: any) => { return data.reduce((csvString: any, rowItem: any) => {
return csvString + columns.map(({ accessor }: any) => escapeCsvCell(accessor(rowItem))).join(',') + '\r\n'; return csvString + columns.map(({ accessor }: any) => escapeCsvCell(accessor(rowItem))).join(';') + '\r\n';
}, columns.map(({ name }: any) => escapeCsvCell(name)).join(',') + '\r\n'); }, columns.map(({ name }: any) => escapeCsvCell(name)).join(';') + '\r\n');
}; };
const downloadAsCsv = (columns: any, data: any, filename: string) => { const downloadAsCsv = (columns: any, data: any, filename: string) => {
const csvData = makeCsvData(columns, data); const csvData = makeCsvData(columns, data);
const csvFile = new Blob([csvData], { type: 'text/csv' }); const csvFile = new Blob([csvData], { type: 'text/csv;charset:utf-8' });
const downloadLink = document.createElement('a'); const downloadLink = document.createElement('a');
downloadLink.download = filename; downloadLink.download = filename;
@@ -384,8 +384,8 @@ const DashboardData: FC = () => {
const handleDownloadCsv = () => { const handleDownloadCsv = () => {
const columns = [ const columns = [
{ accessor: (dv: any) => dv.id.slice(2), name: 'Entity' }, { accessor: (dv: any) => dv.id.slice(2), name: 'Entity' },
{ accessor: (dv: any) => dv.v, name: 'Value' }, { accessor: (dv: any) => (typeof dv.v === 'number') ? new Intl.NumberFormat().format(dv.v) : dv.v, name: 'Value' },
{ accessor: (dv: any) => (dv.u >= 1 && dv.u <= 2 ? 'C' : DeviceValueUOM_s[dv.u]), name: 'UoM' } { accessor: (dv: any) => DeviceValueUOM_s[dv.u], name: 'UoM' }
]; ];
downloadAsCsv( downloadAsCsv(
columns, columns,

View File

@@ -435,15 +435,43 @@ void AnalogSensor::publish_values(const bool force) {
// called from emsesp.cpp, similar to the emsdevice->get_value_info // called from emsesp.cpp, similar to the emsdevice->get_value_info
// searches by name // searches by name
bool AnalogSensor::get_value_info(JsonObject & output, const char * cmd, const int8_t id) const { bool AnalogSensor::get_value_info(JsonObject & output, const char * cmd, const int8_t id) const {
// make a copy of the string command for parsing
char command_s[30];
strlcpy(command_s, cmd, sizeof(command_s));
char * attribute_s = nullptr;
// check specific attribute to fetch instead of the complete record
char * breakp = strchr(command_s, '/');
if (breakp) {
*breakp = '\0';
attribute_s = breakp + 1;
}
for (const auto & sensor : sensors_) { for (const auto & sensor : sensors_) {
if (strcmp(cmd, sensor.name().c_str()) == 0) { if (strcmp(command_s, sensor.name().c_str()) == 0) {
output["gpio"] = sensor.gpio(); output["gpio"] = sensor.gpio();
output["name"] = sensor.name(); output["name"] = sensor.name();
output["type"] = sensor.type(); output["type"] = F_(number);
output["uom"] = sensor.uom(); output["analog"] = FL_(enum_sensortype)[sensor.type()];
output["uom"] = EMSdevice::uom_to_string(sensor.uom());
output["offset"] = sensor.offset(); output["offset"] = sensor.offset();
output["factor"] = sensor.factor(); output["factor"] = sensor.factor();
output["value"] = sensor.value(); output["value"] = sensor.value();
// if we're filtering on an attribute, go find it
if (attribute_s) {
if (output.containsKey(attribute_s)) {
JsonVariant data = output[attribute_s];
output.clear();
output["api_data"] = data;
return true;
} else {
char error[100];
snprintf(error, sizeof(error), "cannot find attribute %s in entity %s", attribute_s, command_s);
output.clear();
output["message"] = error;
return false;
}
}
return true; return true;
} }
} }
@@ -461,7 +489,8 @@ bool AnalogSensor::command_info(const char * value, const int8_t id, JsonObject
if (id == -1) { // show number and id if (id == -1) { // show number and id
JsonObject dataSensor = output.createNestedObject(sensor.name()); JsonObject dataSensor = output.createNestedObject(sensor.name());
dataSensor["gpio"] = sensor.gpio(); dataSensor["gpio"] = sensor.gpio();
dataSensor["type"] = FL_(enum_sensortype)[sensor.type()]; dataSensor["type"] = F_(number);
dataSensor["analog"] = FL_(enum_sensortype)[sensor.type()];
if (sensor.type() == AnalogType::ADC) { if (sensor.type() == AnalogType::ADC) {
dataSensor["uom"] = EMSdevice::uom_to_string(sensor.uom()); dataSensor["uom"] = EMSdevice::uom_to_string(sensor.uom());
dataSensor["offset"] = sensor.offset(); dataSensor["offset"] = sensor.offset();

View File

@@ -90,11 +90,16 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
const char * command_p = nullptr; const char * command_p = nullptr;
if (num_paths == 2) { if (num_paths == 2) {
command_p = p.paths()[1].c_str(); command_p = p.paths()[1].c_str();
} else if (num_paths >= 3) { } else if (num_paths == 3) {
// concatenate the path into one string as it could be in the format 'hc/XXX' // concatenate the path into one string as it could be in the format 'hc/XXX'
char command[50]; char command[50];
snprintf(command, sizeof(command), "%s/%s", p.paths()[1].c_str(), p.paths()[2].c_str()); snprintf(command, sizeof(command), "%s/%s", p.paths()[1].c_str(), p.paths()[2].c_str());
command_p = command; command_p = command;
} else if (num_paths > 3) {
// concatenate the path into one string as it could be in the format 'hc/XXX/attribute'
char command[50];
snprintf(command, sizeof(command), "%s/%s/%s", p.paths()[1].c_str(), p.paths()[2].c_str(), p.paths()[3].c_str());
command_p = command;
} else { } else {
// take it from the JSON // take it from the JSON
if (input.containsKey("entity")) { if (input.containsKey("entity")) {
@@ -110,7 +115,7 @@ uint8_t Command::process(const char * path, const bool is_admin, const JsonObjec
if (command_p == nullptr) { if (command_p == nullptr) {
// handle dead endpoints like api/system or api/boiler // handle dead endpoints like api/system or api/boiler
// default to 'info' for SYSTEM, DALLASENSOR and ANALOGSENSOR, the other devices to 'values' for shortname version // default to 'info' for SYSTEM, DALLASENSOR and ANALOGSENSOR, the other devices to 'values' for shortname version
if (num_paths < 3) { if (num_paths < (id_n > 0 ? 4 : 3)) {
if (device_type < EMSdevice::DeviceType::BOILER) { if (device_type < EMSdevice::DeviceType::BOILER) {
command_p = "info"; command_p = "info";
} else { } else {
@@ -188,37 +193,28 @@ const char * Command::parse_command_string(const char * command, int8_t & id) {
return nullptr; return nullptr;
} }
// make a copy of the string command for parsing if (!strncmp(command, "hc", 2) && strlen(command) >= 3) {
char command_s[30]; id = command[2] - '0';
strlcpy(command_s, command, sizeof(command_s)); command += 3;
} else if (!strncmp(command, "wwc", 3) && strlen(command) >= 4) {
// look for a delimeter and split the string if (command[3] == '1' && command[4] == '0') {
char * p = command_s; id = 19; // wwc10
char * breakp = strchr(p, '.'); command += 5;
if (!breakp) { } else {
p = command_s; // reset and look for / id = command[3] - '0' + 8; // wwc1 has id 9
breakp = strchr(p, '/'); command += 4;
if (!breakp) {
p = command_s; // reset and look for _
breakp = strchr(p, '_');
if (!breakp) {
return command; // no delimeter found, return the whole string
}
} }
} }
// remove separator
// extract the hc or wwc number if (command[0] == '/' || command[0] == '.' || command[0] == '_') {
uint8_t start_pos = breakp - p + 1; command++;
if (!strncmp(command, "hc", 2) && start_pos == 4) { }
id = command[start_pos - 2] - '0'; // return null for empty command
} else if (!strncmp(command, "wwc", 3) && start_pos == 5) { if (command[0] == '\0') {
id = command[start_pos - 2] - '0' + 8; // wwc1 has id 9 return nullptr;
} else {
id = 0; // special case for extracting the attributes
return command;
} }
return (command + start_pos); return command;
} }
// calls a command directly // calls a command directly

View File

@@ -375,8 +375,20 @@ bool DallasSensor::command_info(const char * value, const int8_t id, JsonObject
// called from emsesp.cpp, similar to the emsdevice->get_value_info // called from emsesp.cpp, similar to the emsdevice->get_value_info
bool DallasSensor::get_value_info(JsonObject & output, const char * cmd, const int8_t id) { bool DallasSensor::get_value_info(JsonObject & output, const char * cmd, const int8_t id) {
// make a copy of the string command for parsing
char command_s[30];
strlcpy(command_s, cmd, sizeof(command_s));
char * attribute_s = nullptr;
// check specific attribute to fetch instead of the complete record
char * breakp = strchr(command_s, '/');
if (breakp) {
*breakp = '\0';
attribute_s = breakp + 1;
}
for (const auto & sensor : sensors_) { for (const auto & sensor : sensors_) {
if (strcmp(cmd, sensor.name().c_str()) == 0) { if (strcmp(command_s, sensor.name().c_str()) == 0) {
output["id"] = sensor.id(); output["id"] = sensor.id();
output["name"] = sensor.name(); output["name"] = sensor.name();
if (Helpers::hasValue(sensor.temperature_c)) { if (Helpers::hasValue(sensor.temperature_c)) {
@@ -385,8 +397,23 @@ bool DallasSensor::get_value_info(JsonObject & output, const char * cmd, const i
output["type"] = F_(number); output["type"] = F_(number);
output["min"] = Helpers::round2(-55, 0, EMSESP::system_.fahrenheit() ? 2 : 0); output["min"] = Helpers::round2(-55, 0, EMSESP::system_.fahrenheit() ? 2 : 0);
output["max"] = Helpers::round2(125, 0, EMSESP::system_.fahrenheit() ? 2 : 0); output["max"] = Helpers::round2(125, 0, EMSESP::system_.fahrenheit() ? 2 : 0);
output["unit"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES); output["uom"] = EMSdevice::uom_to_string(DeviceValueUOM::DEGREES);
output["writeable"] = false; output["writeable"] = false;
// if we're filtering on an attribute, go find it
if (attribute_s) {
if (output.containsKey(attribute_s)) {
JsonVariant data = output[attribute_s];
output.clear();
output["api_data"] = data;
return true;
} else {
char error[100];
snprintf(error, sizeof(error), "cannot find attribute %s in entity %s", attribute_s, command_s);
output.clear();
output["message"] = error;
return false;
}
}
return true; return true;
} }
} }

View File

@@ -912,16 +912,13 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
// make a copy of the string command for parsing // make a copy of the string command for parsing
char command_s[30]; char command_s[30];
strlcpy(command_s, cmd, sizeof(command_s)); strlcpy(command_s, cmd, sizeof(command_s));
char * attribute_s = command_s; char * attribute_s = nullptr;
// if id=0 then we have a specific attribute to fetch instead of the complete record // check specific attribute to fetch instead of the complete record
if (id == 0) { char * breakp = strchr(command_s, '/');
char * p = command_s; if (breakp) {
char * breakp = strchr(p, '/'); *breakp = '\0';
if (breakp) { attribute_s = breakp + 1;
*breakp = '\0';
attribute_s = breakp + 1;
}
} }
// search device value with this tag // search device value with this tag
@@ -1065,8 +1062,8 @@ bool EMSdevice::get_value_info(JsonObject & output, const char * cmd, const int8
json[value] = "not set"; json[value] = "not set";
} }
// if id is 0 then we're filtering on an attribute, go find it // if we're filtering on an attribute, go find it
if (id == 0) { if (attribute_s) {
#if defined(EMSESP_DEBUG) #if defined(EMSESP_DEBUG)
EMSESP::logger().debug(F("[DEBUG] Attribute '%s'"), attribute_s); EMSESP::logger().debug(F("[DEBUG] Attribute '%s'"), attribute_s);
#endif #endif