mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 08:49:52 +03:00
Merge pull request #1863 from MichaelDvP/dev
add CMD to api/mqtt to show it in ioBroker, etc.
This commit is contained in:
@@ -465,7 +465,7 @@ const Sensors: FC = () => {
|
|||||||
onClose={onTemperatureDialogClose}
|
onClose={onTemperatureDialogClose}
|
||||||
onSave={onTemperatureDialogSave}
|
onSave={onTemperatureDialogSave}
|
||||||
selectedItem={selectedTemperatureSensor}
|
selectedItem={selectedTemperatureSensor}
|
||||||
validator={temperatureSensorItemValidation()}
|
validator={temperatureSensorItemValidation(sensorData.ts)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{sensorData?.analog_enabled === true && (
|
{sensorData?.analog_enabled === true && (
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import type {
|
|||||||
DeviceValue,
|
DeviceValue,
|
||||||
EntityItem,
|
EntityItem,
|
||||||
ScheduleItem,
|
ScheduleItem,
|
||||||
Settings
|
Settings,
|
||||||
|
TemperatureSensor
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
export const GPIO_VALIDATOR = {
|
export const GPIO_VALIDATOR = {
|
||||||
@@ -288,8 +289,8 @@ export const uniqueNameValidator = (schedule: ScheduleItem[], o_name?: string) =
|
|||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
name !== '' &&
|
name !== '' &&
|
||||||
(o_name === undefined || o_name !== name) &&
|
(o_name === undefined || o_name.toLowerCase() !== name.toLowerCase()) &&
|
||||||
schedule.find((si) => si.name === name)
|
schedule.find((si) => si.name.toLowerCase() === name.toLowerCase())
|
||||||
) {
|
) {
|
||||||
callback('Name already in use');
|
callback('Name already in use');
|
||||||
} else {
|
} else {
|
||||||
@@ -306,8 +307,8 @@ export const schedulerItemValidation = (
|
|||||||
name: [
|
name: [
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
pattern: /^[a-zA-Z0-9_\\.]{0,15}$/,
|
pattern: /^[a-zA-Z0-9_\\.]{0,19}$/,
|
||||||
message: "Must be <15 characters: alpha numeric, '_' or '.'"
|
message: "Must be <20 characters: alpha numeric, '_' or '.'"
|
||||||
},
|
},
|
||||||
...[uniqueNameValidator(schedule, scheduleItem.o_name)]
|
...[uniqueNameValidator(schedule, scheduleItem.o_name)]
|
||||||
],
|
],
|
||||||
@@ -332,8 +333,8 @@ export const uniqueCustomNameValidator = (
|
|||||||
callback: (error?: string) => void
|
callback: (error?: string) => void
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
(o_name === undefined || o_name !== name) &&
|
(o_name === undefined || o_name.toLowerCase() !== name.toLowerCase()) &&
|
||||||
entity.find((ei) => ei.name === name)
|
entity.find((ei) => ei.name.toLowerCase() === name.toLowerCase())
|
||||||
) {
|
) {
|
||||||
callback('Name already in use');
|
callback('Name already in use');
|
||||||
} else {
|
} else {
|
||||||
@@ -348,8 +349,8 @@ export const entityItemValidation = (entity: EntityItem[], entityItem: EntityIte
|
|||||||
{ required: true, message: 'Name is required' },
|
{ required: true, message: 'Name is required' },
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
pattern: /^[a-zA-Z0-9_\\.]{1,15}$/,
|
pattern: /^[a-zA-Z0-9_\\.]{1,19}$/,
|
||||||
message: "Must be <15 characters: alpha numeric, '_' or '.'"
|
message: "Must be <20 characters: alpha numeric, '_' or '.'"
|
||||||
},
|
},
|
||||||
...[uniqueCustomNameValidator(entity, entityItem.o_name)]
|
...[uniqueCustomNameValidator(entity, entityItem.o_name)]
|
||||||
],
|
],
|
||||||
@@ -387,14 +388,25 @@ export const entityItemValidation = (entity: EntityItem[], entityItem: EntityIte
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
export const temperatureSensorItemValidation = () =>
|
export const uniqueTemperatureNameValidator = (sensors: TemperatureSensor[]) => ({
|
||||||
|
validator(rule: InternalRuleItem, n: string, callback: (error?: string) => void) {
|
||||||
|
if (n !== '' && sensors.find((ts) => ts.n.toLowerCase() === n.toLowerCase())) {
|
||||||
|
callback('Name already in use');
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const temperatureSensorItemValidation = (sensors: TemperatureSensor[]) =>
|
||||||
new Schema({
|
new Schema({
|
||||||
n: [
|
n: [
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
pattern: /^[a-zA-Z0-9_\\.]{0,17}$/,
|
pattern: /^[a-zA-Z0-9_\\.]{0,19}$/,
|
||||||
message: "Must be <18 characters: alpha numeric, '_' or '.'"
|
message: "Must be <20 characters: alpha numeric, '_' or '.'"
|
||||||
}
|
},
|
||||||
|
...[uniqueTemperatureNameValidator(sensors)]
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -412,13 +424,30 @@ export const isGPIOUniqueValidator = (sensors: AnalogSensor[]) => ({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const uniqueAnalogNameValidator = (sensors: AnalogSensor[]) => ({
|
||||||
|
validator(rule: InternalRuleItem, n: string, callback: (error?: string) => void) {
|
||||||
|
if (n !== '' && sensors.find((as) => as.n.toLowerCase() === n.toLowerCase())) {
|
||||||
|
callback('Name already in use');
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
export const analogSensorItemValidation = (
|
export const analogSensorItemValidation = (
|
||||||
sensors: AnalogSensor[],
|
sensors: AnalogSensor[],
|
||||||
creating: boolean,
|
creating: boolean,
|
||||||
platform: string
|
platform: string
|
||||||
) =>
|
) =>
|
||||||
new Schema({
|
new Schema({
|
||||||
n: [{ required: true, message: 'Name is required' }],
|
n: [
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
pattern: /^[a-zA-Z0-9_\\.]{0,19}$/,
|
||||||
|
message: "Must be <20 characters: alpha numeric, '_' or '.'"
|
||||||
|
},
|
||||||
|
...[uniqueAnalogNameValidator(sensors)]
|
||||||
|
],
|
||||||
g: [
|
g: [
|
||||||
{ required: true, message: 'GPIO is required' },
|
{ required: true, message: 'GPIO is required' },
|
||||||
platform === 'ESP32-S3'
|
platform === 'ESP32-S3'
|
||||||
|
|||||||
@@ -711,7 +711,7 @@ bool AnalogSensor::get_value_info(JsonObject output, const char * cmd, const int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return EMSESP::return_not_found(output, "analog sensor", cmd); // not found
|
return EMSESP::return_not_found(output, cmd, F_(analogsensor)); // not found
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnalogSensor::addSensorJson(JsonObject output, const Sensor & sensor) {
|
void AnalogSensor::addSensorJson(JsonObject output, const Sensor & sensor) {
|
||||||
@@ -759,8 +759,8 @@ AnalogSensor::Sensor::Sensor(const uint8_t gpio, const std::string & name, const
|
|||||||
// returns name of the analog sensor or creates one if its empty
|
// returns name of the analog sensor or creates one if its empty
|
||||||
std::string AnalogSensor::Sensor::name() const {
|
std::string AnalogSensor::Sensor::name() const {
|
||||||
if (name_.empty()) {
|
if (name_.empty()) {
|
||||||
char name[50];
|
char name[20];
|
||||||
snprintf(name, sizeof(name), "Analog Sensor GPIO %02d", gpio_);
|
snprintf(name, sizeof(name), "%s_%02d", FL_(AnalogTypeName)[type_], gpio_);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
return name_;
|
return name_;
|
||||||
|
|||||||
@@ -27,6 +27,9 @@
|
|||||||
|
|
||||||
namespace emsesp {
|
namespace emsesp {
|
||||||
|
|
||||||
|
// names, same order as AnalogType
|
||||||
|
MAKE_ENUM_FIXED(AnalogTypeName, "disabled", "dig_in", "counter", "adc", "timer", "rate", "pwm0", "pwm1", "pwm2")
|
||||||
|
|
||||||
class AnalogSensor {
|
class AnalogSensor {
|
||||||
public:
|
public:
|
||||||
class Sensor {
|
class Sensor {
|
||||||
|
|||||||
@@ -318,15 +318,17 @@ uint8_t Command::call(const uint8_t device_type, const char * cmd, const char *
|
|||||||
|
|
||||||
// determine flags based on id (which is the tag)
|
// determine flags based on id (which is the tag)
|
||||||
uint8_t flag = CommandFlag::CMD_FLAG_DEFAULT;
|
uint8_t flag = CommandFlag::CMD_FLAG_DEFAULT;
|
||||||
int8_t tag = id;
|
// info and values works with all tags, keep it default
|
||||||
if (tag >= DeviceValueTAG::TAG_HC1 && tag <= DeviceValueTAG::TAG_HC8) {
|
if (std::string(cmd) != F_(values) && std::string(cmd) != F_(info)) {
|
||||||
flag = CommandFlag::CMD_FLAG_HC;
|
if (id >= DeviceValueTAG::TAG_HC1 && id <= DeviceValueTAG::TAG_HC8) {
|
||||||
} else if (tag >= DeviceValueTAG::TAG_DHW1 && tag <= DeviceValueTAG::TAG_DHW10) {
|
flag = CommandFlag::CMD_FLAG_HC;
|
||||||
flag = CommandFlag::CMD_FLAG_DHW;
|
} else if (id >= DeviceValueTAG::TAG_DHW1 && id <= DeviceValueTAG::TAG_DHW10) {
|
||||||
} else if (tag >= DeviceValueTAG::TAG_HS1 && tag <= DeviceValueTAG::TAG_HS16) {
|
flag = CommandFlag::CMD_FLAG_DHW;
|
||||||
flag = CommandFlag::CMD_FLAG_HS;
|
} else if (id >= DeviceValueTAG::TAG_HS1 && id <= DeviceValueTAG::TAG_HS16) {
|
||||||
} else if (tag >= DeviceValueTAG::TAG_AHS1 && tag <= DeviceValueTAG::TAG_AHS1) {
|
flag = CommandFlag::CMD_FLAG_HS;
|
||||||
flag = CommandFlag::CMD_FLAG_AHS;
|
} else if (id >= DeviceValueTAG::TAG_AHS1 && id <= DeviceValueTAG::TAG_AHS1) {
|
||||||
|
flag = CommandFlag::CMD_FLAG_AHS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// first see if there is a command registered and it's valid
|
// first see if there is a command registered and it's valid
|
||||||
|
|||||||
@@ -519,7 +519,6 @@ void EMSdevice::add_device_value(int8_t tag, // to b
|
|||||||
uint32_t max // max allowed value
|
uint32_t max // max allowed value
|
||||||
) {
|
) {
|
||||||
// initialize the device value depending on it's type
|
// initialize the device value depending on it's type
|
||||||
// ignoring DeviceValueType::CMD
|
|
||||||
|
|
||||||
if (type == DeviceValueType::STRING) {
|
if (type == DeviceValueType::STRING) {
|
||||||
*(char *)(value_p) = {'\0'}; // this is important for string functions like strlen() to work later
|
*(char *)(value_p) = {'\0'}; // this is important for string functions like strlen() to work later
|
||||||
@@ -1549,12 +1548,16 @@ bool EMSdevice::get_value_info(JsonObject output, const char * cmd, const int8_t
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DeviceValueType::CMD:
|
case DeviceValueType::CMD:
|
||||||
json[type] = F_(command);
|
|
||||||
if (dv.options_size > 1) {
|
if (dv.options_size > 1) {
|
||||||
|
json[type] = F_(enum);
|
||||||
JsonArray enum_ = json[F_(enum)].to<JsonArray>();
|
JsonArray enum_ = json[F_(enum)].to<JsonArray>();
|
||||||
for (uint8_t i = 0; i < dv.options_size; i++) {
|
for (uint8_t i = 0; i < dv.options_size; i++) {
|
||||||
enum_.add(Helpers::translated_word(dv.options[i]));
|
enum_.add(Helpers::translated_word(dv.options[i]));
|
||||||
}
|
}
|
||||||
|
} else if (dv.uom != DeviceValueUOM::NONE) {
|
||||||
|
json[type] = F_(number);
|
||||||
|
} else {
|
||||||
|
json[type] = F_(command);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1585,10 +1588,11 @@ bool EMSdevice::get_value_info(JsonObject output, const char * cmd, const int8_t
|
|||||||
// TODO refactor to remove containsKey as it's costly and not advisable to use it
|
// TODO refactor to remove containsKey as it's costly and not advisable to use it
|
||||||
// https://arduinojson.org/v7/api/jsonobject/containskey/#avoid
|
// https://arduinojson.org/v7/api/jsonobject/containskey/#avoid
|
||||||
|
|
||||||
|
// commented out, leads to issues if type is set to number
|
||||||
// if there is no value, mention it
|
// if there is no value, mention it
|
||||||
if (!json.containsKey(value)) {
|
// if (!json.containsKey(value)) {
|
||||||
json[value] = "not set";
|
// json[value] = "not set";
|
||||||
}
|
// }
|
||||||
|
|
||||||
// if we're filtering on an attribute, go find it
|
// if we're filtering on an attribute, go find it
|
||||||
if (attribute_s) {
|
if (attribute_s) {
|
||||||
@@ -1756,10 +1760,14 @@ bool EMSdevice::generate_values(JsonObject output, const int8_t tag_filter, cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// commenting out as we don't want Commands in Console ('show values')
|
// we don't want Commands in Console ('show values')
|
||||||
// else if (dv.type == DeviceValueType::CMD && output_target != EMSdevice::OUTPUT_TARGET::MQTT) {
|
else if (dv.type == DeviceValueType::CMD && output_target != EMSdevice::OUTPUT_TARGET::CONSOLE) {
|
||||||
// json[name] = "";
|
if (dv.uom == DeviceValueUOM::NONE) {
|
||||||
// }
|
json[name] = "";
|
||||||
|
} else {
|
||||||
|
json[name] = NAN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check for value outside min/max range and adapt the limits to avoid HA complains
|
// check for value outside min/max range and adapt the limits to avoid HA complains
|
||||||
// Should this also check for api output?
|
// Should this also check for api output?
|
||||||
|
|||||||
@@ -1302,7 +1302,7 @@ bool System::get_value_info(JsonObject root, const char * command) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char cmd[COMMAND_MAX_LENGTH];
|
char cmd[COMMAND_MAX_LENGTH];
|
||||||
strlcpy(cmd, command, sizeof(cmd));
|
strlcpy(cmd, Helpers::toLower(command).c_str(), sizeof(cmd));
|
||||||
char * val = strstr(cmd, "/value");
|
char * val = strstr(cmd, "/value");
|
||||||
if (val) {
|
if (val) {
|
||||||
val[0] = '\0';
|
val[0] = '\0';
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ bool TemperatureSensor::get_value_info(JsonObject output, const char * cmd, cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return EMSESP::return_not_found(output, "temperature sensor", cmd); // not found
|
return EMSESP::return_not_found(output, cmd, F_(temperaturesensor)); // not found
|
||||||
}
|
}
|
||||||
|
|
||||||
void TemperatureSensor::addSensorJson(JsonObject output, const Sensor & sensor) {
|
void TemperatureSensor::addSensorJson(JsonObject output, const Sensor & sensor) {
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ bool WebCustomEntityService::get_value_info(JsonObject output, const char * cmd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return EMSESP::return_not_found(output, "custom entity", cmd); // not found
|
return EMSESP::return_not_found(output, cmd, F_(custom)); // not found
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish single value
|
// publish single value
|
||||||
|
|||||||
@@ -161,11 +161,7 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output.size()) {
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return EMSESP::return_not_found(output, "schedule", cmd); // not found
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char command_s[COMMAND_MAX_LENGTH];
|
char command_s[COMMAND_MAX_LENGTH];
|
||||||
@@ -210,7 +206,7 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return EMSESP::return_not_found(output, "schedule", cmd); // not found
|
return EMSESP::return_not_found(output, cmd, F_(scheduler)); // not found
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish single value
|
// publish single value
|
||||||
|
|||||||
Reference in New Issue
Block a user