mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-08 00:39:50 +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}
|
||||
onSave={onTemperatureDialogSave}
|
||||
selectedItem={selectedTemperatureSensor}
|
||||
validator={temperatureSensorItemValidation()}
|
||||
validator={temperatureSensorItemValidation(sensorData.ts)}
|
||||
/>
|
||||
)}
|
||||
{sensorData?.analog_enabled === true && (
|
||||
|
||||
@@ -7,7 +7,8 @@ import type {
|
||||
DeviceValue,
|
||||
EntityItem,
|
||||
ScheduleItem,
|
||||
Settings
|
||||
Settings,
|
||||
TemperatureSensor
|
||||
} from './types';
|
||||
|
||||
export const GPIO_VALIDATOR = {
|
||||
@@ -288,8 +289,8 @@ export const uniqueNameValidator = (schedule: ScheduleItem[], o_name?: string) =
|
||||
) {
|
||||
if (
|
||||
name !== '' &&
|
||||
(o_name === undefined || o_name !== name) &&
|
||||
schedule.find((si) => si.name === name)
|
||||
(o_name === undefined || o_name.toLowerCase() !== name.toLowerCase()) &&
|
||||
schedule.find((si) => si.name.toLowerCase() === name.toLowerCase())
|
||||
) {
|
||||
callback('Name already in use');
|
||||
} else {
|
||||
@@ -306,8 +307,8 @@ export const schedulerItemValidation = (
|
||||
name: [
|
||||
{
|
||||
type: 'string',
|
||||
pattern: /^[a-zA-Z0-9_\\.]{0,15}$/,
|
||||
message: "Must be <15 characters: alpha numeric, '_' or '.'"
|
||||
pattern: /^[a-zA-Z0-9_\\.]{0,19}$/,
|
||||
message: "Must be <20 characters: alpha numeric, '_' or '.'"
|
||||
},
|
||||
...[uniqueNameValidator(schedule, scheduleItem.o_name)]
|
||||
],
|
||||
@@ -332,8 +333,8 @@ export const uniqueCustomNameValidator = (
|
||||
callback: (error?: string) => void
|
||||
) {
|
||||
if (
|
||||
(o_name === undefined || o_name !== name) &&
|
||||
entity.find((ei) => ei.name === name)
|
||||
(o_name === undefined || o_name.toLowerCase() !== name.toLowerCase()) &&
|
||||
entity.find((ei) => ei.name.toLowerCase() === name.toLowerCase())
|
||||
) {
|
||||
callback('Name already in use');
|
||||
} else {
|
||||
@@ -348,8 +349,8 @@ export const entityItemValidation = (entity: EntityItem[], entityItem: EntityIte
|
||||
{ required: true, message: 'Name is required' },
|
||||
{
|
||||
type: 'string',
|
||||
pattern: /^[a-zA-Z0-9_\\.]{1,15}$/,
|
||||
message: "Must be <15 characters: alpha numeric, '_' or '.'"
|
||||
pattern: /^[a-zA-Z0-9_\\.]{1,19}$/,
|
||||
message: "Must be <20 characters: alpha numeric, '_' or '.'"
|
||||
},
|
||||
...[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({
|
||||
n: [
|
||||
{
|
||||
type: 'string',
|
||||
pattern: /^[a-zA-Z0-9_\\.]{0,17}$/,
|
||||
message: "Must be <18 characters: alpha numeric, '_' or '.'"
|
||||
}
|
||||
pattern: /^[a-zA-Z0-9_\\.]{0,19}$/,
|
||||
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 = (
|
||||
sensors: AnalogSensor[],
|
||||
creating: boolean,
|
||||
platform: string
|
||||
) =>
|
||||
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: [
|
||||
{ required: true, message: 'GPIO is required' },
|
||||
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) {
|
||||
@@ -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
|
||||
std::string AnalogSensor::Sensor::name() const {
|
||||
if (name_.empty()) {
|
||||
char name[50];
|
||||
snprintf(name, sizeof(name), "Analog Sensor GPIO %02d", gpio_);
|
||||
char name[20];
|
||||
snprintf(name, sizeof(name), "%s_%02d", FL_(AnalogTypeName)[type_], gpio_);
|
||||
return name;
|
||||
}
|
||||
return name_;
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
// names, same order as AnalogType
|
||||
MAKE_ENUM_FIXED(AnalogTypeName, "disabled", "dig_in", "counter", "adc", "timer", "rate", "pwm0", "pwm1", "pwm2")
|
||||
|
||||
class AnalogSensor {
|
||||
public:
|
||||
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)
|
||||
uint8_t flag = CommandFlag::CMD_FLAG_DEFAULT;
|
||||
int8_t tag = id;
|
||||
if (tag >= DeviceValueTAG::TAG_HC1 && tag <= DeviceValueTAG::TAG_HC8) {
|
||||
flag = CommandFlag::CMD_FLAG_HC;
|
||||
} else if (tag >= DeviceValueTAG::TAG_DHW1 && tag <= DeviceValueTAG::TAG_DHW10) {
|
||||
flag = CommandFlag::CMD_FLAG_DHW;
|
||||
} else if (tag >= DeviceValueTAG::TAG_HS1 && tag <= DeviceValueTAG::TAG_HS16) {
|
||||
flag = CommandFlag::CMD_FLAG_HS;
|
||||
} else if (tag >= DeviceValueTAG::TAG_AHS1 && tag <= DeviceValueTAG::TAG_AHS1) {
|
||||
flag = CommandFlag::CMD_FLAG_AHS;
|
||||
// info and values works with all tags, keep it default
|
||||
if (std::string(cmd) != F_(values) && std::string(cmd) != F_(info)) {
|
||||
if (id >= DeviceValueTAG::TAG_HC1 && id <= DeviceValueTAG::TAG_HC8) {
|
||||
flag = CommandFlag::CMD_FLAG_HC;
|
||||
} else if (id >= DeviceValueTAG::TAG_DHW1 && id <= DeviceValueTAG::TAG_DHW10) {
|
||||
flag = CommandFlag::CMD_FLAG_DHW;
|
||||
} else if (id >= DeviceValueTAG::TAG_HS1 && id <= DeviceValueTAG::TAG_HS16) {
|
||||
flag = CommandFlag::CMD_FLAG_HS;
|
||||
} 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
|
||||
|
||||
@@ -519,7 +519,6 @@ void EMSdevice::add_device_value(int8_t tag, // to b
|
||||
uint32_t max // max allowed value
|
||||
) {
|
||||
// initialize the device value depending on it's type
|
||||
// ignoring DeviceValueType::CMD
|
||||
|
||||
if (type == DeviceValueType::STRING) {
|
||||
*(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;
|
||||
|
||||
case DeviceValueType::CMD:
|
||||
json[type] = F_(command);
|
||||
if (dv.options_size > 1) {
|
||||
json[type] = F_(enum);
|
||||
JsonArray enum_ = json[F_(enum)].to<JsonArray>();
|
||||
for (uint8_t i = 0; i < dv.options_size; 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;
|
||||
|
||||
@@ -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
|
||||
// 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 (!json.containsKey(value)) {
|
||||
json[value] = "not set";
|
||||
}
|
||||
// if (!json.containsKey(value)) {
|
||||
// json[value] = "not set";
|
||||
// }
|
||||
|
||||
// if we're filtering on an attribute, go find it
|
||||
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')
|
||||
// else if (dv.type == DeviceValueType::CMD && output_target != EMSdevice::OUTPUT_TARGET::MQTT) {
|
||||
// json[name] = "";
|
||||
// }
|
||||
// we don't want Commands in Console ('show values')
|
||||
else if (dv.type == DeviceValueType::CMD && output_target != EMSdevice::OUTPUT_TARGET::CONSOLE) {
|
||||
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
|
||||
// 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];
|
||||
strlcpy(cmd, command, sizeof(cmd));
|
||||
strlcpy(cmd, Helpers::toLower(command).c_str(), sizeof(cmd));
|
||||
char * val = strstr(cmd, "/value");
|
||||
if (val) {
|
||||
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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -161,11 +161,7 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
if (output.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return EMSESP::return_not_found(output, "schedule", cmd); // not found
|
||||
return true;
|
||||
}
|
||||
|
||||
char command_s[COMMAND_MAX_LENGTH];
|
||||
@@ -210,7 +206,7 @@ bool WebSchedulerService::get_value_info(JsonObject output, const char * cmd) {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user