Merge pull request #1863 from MichaelDvP/dev

add CMD to api/mqtt to show it in ioBroker, etc.
This commit is contained in:
Proddy
2024-07-15 11:42:41 +02:00
committed by GitHub
10 changed files with 83 additions and 45 deletions

View File

@@ -465,7 +465,7 @@ const Sensors: FC = () => {
onClose={onTemperatureDialogClose}
onSave={onTemperatureDialogSave}
selectedItem={selectedTemperatureSensor}
validator={temperatureSensorItemValidation()}
validator={temperatureSensorItemValidation(sensorData.ts)}
/>
)}
{sensorData?.analog_enabled === true && (

View File

@@ -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'

View File

@@ -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_;

View File

@@ -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 {

View File

@@ -318,16 +318,18 @@ 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) {
// 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 (tag >= DeviceValueTAG::TAG_DHW1 && tag <= DeviceValueTAG::TAG_DHW10) {
} else if (id >= DeviceValueTAG::TAG_DHW1 && id <= DeviceValueTAG::TAG_DHW10) {
flag = CommandFlag::CMD_FLAG_DHW;
} else if (tag >= DeviceValueTAG::TAG_HS1 && tag <= DeviceValueTAG::TAG_HS16) {
} else if (id >= DeviceValueTAG::TAG_HS1 && id <= DeviceValueTAG::TAG_HS16) {
flag = CommandFlag::CMD_FLAG_HS;
} else if (tag >= DeviceValueTAG::TAG_AHS1 && tag <= DeviceValueTAG::TAG_AHS1) {
} 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
auto cf = find_command(device_type, device_id, cmd, flag);

View File

@@ -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?

View File

@@ -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';

View File

@@ -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) {

View File

@@ -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

View File

@@ -161,13 +161,9 @@ 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
}
char command_s[COMMAND_MAX_LENGTH];
strlcpy(command_s, Helpers::toLower(cmd).c_str(), sizeof(command_s));
char * attribute_s = nullptr;
@@ -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