sensor is only non-null after a successful init(), so isInitialized() can
just check the pointer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
isInitialized() now also requires a valid sensor pointer, so plugin_read()
and plugin_write() never dereference a null sensor. setOutputValues() checks
it as well, and init() deletes a previous sensor object before allocating a
new one, so calling it again does not leak.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hideEscaped(), hideMasked() and restoreMaskedAndEscaped() are only used in
ESPEasyRules.cpp. With internal linkage GCC inlines them where they are
called once (builds without FEATURE_EXTENDED_STRING_FUNCTIONS), so the
ESP8266 build is the same size as before the previous commit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
parse_string_commands() had #else copies of hideEscaped(), hideMasked()
and restoreMaskedAndEscaped() for builds without
FEATURE_EXTENDED_STRING_FUNCTIONS, and the previous commit fixed a bug in
one of those copies. Build the helpers always and keep only the escaped
colon (\:) handling under FEATURE_EXTENDED_STRING_FUNCTIONS, the same as
in stripEscapeCharacters() / addEscapeCharacters().
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In parse_string_commands() the branch without FEATURE_EXTENDED_STRING_FUNCTIONS
masked '{' and '}' in the whole line instead of in replacement (regression from
4e191fc5b). The following line.replace() put the unmasked braces back, so
get_next_inner_bracket() found them again and the loop never ended
(SW watchdog / exception reset). Mask replacement, as before 4e191fc5b.
Fixes #5653
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Regression from #5369: P056_data_struct::ReadAverage() took float pm25/pm10 by value, so the averaged values never reached the caller and the task values stayed 0. Pass them by reference like CjkSDS011::ReadAverage().