removed Env MQTT topic
This commit is contained in:
parent
8eda0b4a36
commit
cd8491dcc0
|
|
@ -107,6 +107,13 @@ scripts for this are worth keeping; note that wrapping them in `timeout` SIGTERM
|
||||||
|
|
||||||
## Possible follow-ups (not done)
|
## Possible follow-ups (not done)
|
||||||
|
|
||||||
|
- **A retained `Env` payload may still sit on the broker.** `GGS/FWT/<tower>/Env` was
|
||||||
|
published retained until it was removed, so a broker that saw the old build still holds
|
||||||
|
the last ambient reading and hands it to every new subscriber — a frozen temperature and
|
||||||
|
humidity with an old timestamp, indistinguishable from a sensor that stopped reporting.
|
||||||
|
Nothing in the code does this any more, so nothing here would otherwise explain it.
|
||||||
|
Clear it broker-side by publishing a zero-length retained message to that topic.
|
||||||
|
|
||||||
- **NWU vs ENU is decided by a constant, not by the device.** `kMtiReference`
|
- **NWU vs ENU is decided by a constant, not by the device.** `kMtiReference`
|
||||||
([MtiProtocol.h](../include/fgc/MtiProtocol.h)) says the MTi reports against NWU, and the
|
([MtiProtocol.h](../include/fgc/MtiProtocol.h)) says the MTi reports against NWU, and the
|
||||||
host re-references it to NED. The two candidates give *identical* roll and pitch and
|
host re-references it to NED. The two candidates give *identical* roll and pitch and
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ Per-file reference for the refactored tree, plus the shared data structures.
|
||||||
| [include/fgc/sensors/Sht41Protocol.h](../include/fgc/sensors/Sht41Protocol.h), [src/sensors/Sht41Protocol.cpp](../src/sensors/Sht41Protocol.cpp) | Sensirion SHT4x wire protocol, pure: command bytes, `sht41Crc8` (poly 0x31/init 0xFF), `decodeSht41Measurement` (6-byte response → `Sht41Reading`, CRC-checked, raw→°C/%RH with RH clamped 0..100) |
|
| [include/fgc/sensors/Sht41Protocol.h](../include/fgc/sensors/Sht41Protocol.h), [src/sensors/Sht41Protocol.cpp](../src/sensors/Sht41Protocol.cpp) | Sensirion SHT4x wire protocol, pure: command bytes, `sht41Crc8` (poly 0x31/init 0xFF), `decodeSht41Measurement` (6-byte response → `Sht41Reading`, CRC-checked, raw→°C/%RH with RH clamped 0..100) |
|
||||||
| [include/fgc/CameraProfile.h](../include/fgc/CameraProfile.h), [src/core/CameraProfile.cpp](../src/core/CameraProfile.cpp) | `loadCameraProfile` / `loadCameraProfiles`: one VimbaX settings XML per profile. Hashes the XML, regenerates the `.txt` record when it changes, and reports which settings moved. A missing XML throws — the record is never a fallback |
|
| [include/fgc/CameraProfile.h](../include/fgc/CameraProfile.h), [src/core/CameraProfile.cpp](../src/core/CameraProfile.cpp) | `loadCameraProfile` / `loadCameraProfiles`: one VimbaX settings XML per profile. Hashes the XML, regenerates the `.txt` record when it changes, and reports which settings moved. A missing XML throws — the record is never a fallback |
|
||||||
| [include/fgc/CameraSettingsXml.h](../include/fgc/CameraSettingsXml.h), [src/core/CameraSettingsXml.cpp](../src/core/CameraSettingsXml.cpp) | Parses the Viewer export's `<RemoteDevice>` features (ordered, selector-aware), renders the human-readable `.txt` record, reads one back, and diffs two settings lists. Used for display and change detection only — never to configure a camera |
|
| [include/fgc/CameraSettingsXml.h](../include/fgc/CameraSettingsXml.h), [src/core/CameraSettingsXml.cpp](../src/core/CameraSettingsXml.cpp) | Parses the Viewer export's `<RemoteDevice>` features (ordered, selector-aware), renders the human-readable `.txt` record, reads one back, and diffs two settings lists. Used for display and change detection only — never to configure a camera |
|
||||||
| [include/fgc/ChannelTopics.h](../include/fgc/ChannelTopics.h), [src/core/ChannelTopics.cpp](../src/core/ChannelTopics.cpp) | The MQTT wire format in one place: topic builders for the `GGS/FWT/<tower>/…` tree and the `CamEvent`/`EnvEvent`/status payload builders. Pure, so the documented format is unit-tested rather than assembled inline at each publish site |
|
| [include/fgc/ChannelTopics.h](../include/fgc/ChannelTopics.h), [src/core/ChannelTopics.cpp](../src/core/ChannelTopics.cpp) | The MQTT wire format in one place: topic builders for the `GGS/FWT/<tower>/…` tree and the `CamEvent`/status payload builders. Pure, so the documented format is unit-tested rather than assembled inline at each publish site |
|
||||||
| [include/fgc/ChannelHistory.h](../include/fgc/ChannelHistory.h), [src/core/ChannelHistory.cpp](../src/core/ChannelHistory.cpp) | Ring buffer of recently published messages (time, topic, payload, outcome) plus the delivery counters — sent, failed, connects, losses, last status. Feeds the expanded Connectivity view so a publish can be confirmed without a broker-side subscriber |
|
| [include/fgc/ChannelHistory.h](../include/fgc/ChannelHistory.h), [src/core/ChannelHistory.cpp](../src/core/ChannelHistory.cpp) | Ring buffer of recently published messages (time, topic, payload, outcome) plus the delivery counters — sent, failed, connects, losses, last status. Feeds the expanded Connectivity view so a publish can be confirmed without a broker-side subscriber |
|
||||||
| [include/fgc/Hash.h](../include/fgc/Hash.h), [src/core/Hash.cpp](../src/core/Hash.cpp) | FNV-1a 64 over a string or a file, with an algorithm-prefixed label. Change detection for the profile records, deliberately not a crypto hash |
|
| [include/fgc/Hash.h](../include/fgc/Hash.h), [src/core/Hash.cpp](../src/core/Hash.cpp) | FNV-1a 64 over a string or a file, with an algorithm-prefixed label. Change detection for the profile records, deliberately not a crypto hash |
|
||||||
| [include/fgc/CaptureScheduler.h](../include/fgc/CaptureScheduler.h), [src/core/CaptureScheduler.cpp](../src/core/CaptureScheduler.cpp) | Capture state machine over the interfaces; injectable clock; `setGeometry` adopts a recalibration |
|
| [include/fgc/CaptureScheduler.h](../include/fgc/CaptureScheduler.h), [src/core/CaptureScheduler.cpp](../src/core/CaptureScheduler.cpp) | Capture state machine over the interfaces; injectable clock; `setGeometry` adopts a recalibration |
|
||||||
|
|
@ -38,7 +38,7 @@ Per-file reference for the refactored tree, plus the shared data structures.
|
||||||
| File | Interface | Shared structs |
|
| File | Interface | Shared structs |
|
||||||
|------|-----------|----------------|
|
|------|-----------|----------------|
|
||||||
| [include/fgc/IMotorController.h](../include/fgc/IMotorController.h) | `IMotorController` | `MotorTelemetry` |
|
| [include/fgc/IMotorController.h](../include/fgc/IMotorController.h) | `IMotorController` | `MotorTelemetry` |
|
||||||
| [include/fgc/IControlChannel.h](../include/fgc/IControlChannel.h) | `IControlChannel` | `ControlCommand`, `CamEvent`, `EnvEvent` |
|
| [include/fgc/IControlChannel.h](../include/fgc/IControlChannel.h) | `IControlChannel` | `ControlCommand`, `CamEvent` |
|
||||||
| [include/fgc/ICameraSource.h](../include/fgc/ICameraSource.h) | `ICameraSource` | `Frame` |
|
| [include/fgc/ICameraSource.h](../include/fgc/ICameraSource.h) | `ICameraSource` | `Frame` |
|
||||||
| [include/fgc/IImuSource.h](../include/fgc/IImuSource.h) | `IImuSource` (incl. `config()`, `configProblems()`, `refreshConfig()`, `noRotation()`, `headingReset()`, `setFilterProfile()`) | `ImuSample` (from `MtiProtocol.h`) |
|
| [include/fgc/IImuSource.h](../include/fgc/IImuSource.h) | `IImuSource` (incl. `config()`, `configProblems()`, `refreshConfig()`, `noRotation()`, `headingReset()`, `setFilterProfile()`) | `ImuSample` (from `MtiProtocol.h`) |
|
||||||
| [include/fgc/IEnvSensor.h](../include/fgc/IEnvSensor.h) | `IEnvSensor` (`connected()`, `sample()`, `name()`) | `EnvSample` |
|
| [include/fgc/IEnvSensor.h](../include/fgc/IEnvSensor.h) | `IEnvSensor` (`connected()`, `sample()`, `name()`) | `EnvSample` |
|
||||||
|
|
@ -98,10 +98,6 @@ homing or `gimbal reset`, so a lit badge means "position untrustworthy since the
|
||||||
`tower`, `camera` (RGB/ACR/NIR), `heading_decideg` (yaw×10), `pitch_decideg` (pitch×10) and
|
`tower`, `camera` (RGB/ACR/NIR), `heading_decideg` (yaw×10), `pitch_decideg` (pitch×10) and
|
||||||
`timestamp_ms` (which matches the image filename). Serialized to the CamEvent JSON payload (see [mqtt-api.md](mqtt-api.md)).
|
`timestamp_ms` (which matches the image filename). Serialized to the CamEvent JSON payload (see [mqtt-api.md](mqtt-api.md)).
|
||||||
|
|
||||||
### `EnvEvent` ([IControlChannel.h](../include/fgc/IControlChannel.h))
|
|
||||||
`tower`, `temp_c`, `humidity_pct`, `timestamp_ms`. Published once per **fresh** sample (deduplicated
|
|
||||||
on `timestamp_ms`, not per control-loop tick) to the `Env` topic — see [mqtt-api.md](mqtt-api.md).
|
|
||||||
|
|
||||||
### `EnvSample` ([IEnvSensor.h](../include/fgc/IEnvSensor.h))
|
### `EnvSample` ([IEnvSensor.h](../include/fgc/IEnvSensor.h))
|
||||||
One ambient reading: `valid`, `temp_c` (°C), `humidity_pct` (0..100), `timestamp_ms` (epoch ms).
|
One ambient reading: `valid`, `temp_c` (°C), `humidity_pct` (0..100), `timestamp_ms` (epoch ms).
|
||||||
`IEnvSensor::sample()` returns `nullopt` rather than a stale sample once nothing valid has arrived
|
`IEnvSensor::sample()` returns `nullopt` rather than a stale sample once nothing valid has arrived
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ When a ControlCode message arrives, the program echoes the current code back on
|
||||||
|-------|------|---------|--------------|
|
|-------|------|---------|--------------|
|
||||||
| `GGS/FWT/<tower>/StatusCode` | At startup (`"0"`); whenever a ControlCode message is received (echoes the code) | integer as string | 1 / retained |
|
| `GGS/FWT/<tower>/StatusCode` | At startup (`"0"`); whenever a ControlCode message is received (echoes the code) | integer as string | 1 / retained |
|
||||||
| `GGS/FWT/<tower>/CamEvent` | After each image is saved | JSON object (below) | 1 / retained |
|
| `GGS/FWT/<tower>/CamEvent` | After each image is saved | JSON object (below) | 1 / retained |
|
||||||
| `GGS/FWT/<tower>/Env` | Once per fresh ambient sensor sample (see `[Env] period_ms`) | JSON object (below) | 1 / retained |
|
|
||||||
|
|
||||||
### CamEvent payload
|
### CamEvent payload
|
||||||
|
|
||||||
|
|
@ -101,22 +100,6 @@ Both `hdg` and `pit` are sampled **when the frame arrives**, not when its JPEG X
|
||||||
finishes, so a slow encode or a backed-up queue cannot attribute a later pose to earlier
|
finishes, so a slow encode or a backed-up queue cannot attribute a later pose to earlier
|
||||||
pixels.
|
pixels.
|
||||||
|
|
||||||
### Env payload
|
|
||||||
|
|
||||||
Built by `MqttControlChannel::publishEnv` from an `EnvEvent`, sourced from whichever `IEnvSensor` backend is
|
|
||||||
active (SHT41 on the LattePanda's own I2C bus by default; see [configuration.md](configuration.md)):
|
|
||||||
|
|
||||||
```json
|
|
||||||
{ "fwt":"ExampleTower", "temp_c":22.4, "humid_pct":46.1, "time":1719312345678 }
|
|
||||||
```
|
|
||||||
|
|
||||||
| Field | Type | Meaning |
|
|
||||||
|-------|------|---------|
|
|
||||||
| `fwt` | string | Tower name (`config.ini` `tower_name`) |
|
|
||||||
| `temp_c` | float | Ambient temperature, °C |
|
|
||||||
| `humid_pct` | float | Ambient relative humidity, % |
|
|
||||||
| `time` | int | Sample timestamp, Unix epoch **milliseconds** |
|
|
||||||
|
|
||||||
## Topic summary
|
## Topic summary
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
@ -125,7 +108,6 @@ subscribe: GGS/FWT/<tower>/target_HDG (int heading)
|
||||||
|
|
||||||
publish: GGS/FWT/<tower>/StatusCode (echoed control code)
|
publish: GGS/FWT/<tower>/StatusCode (echoed control code)
|
||||||
GGS/FWT/<tower>/CamEvent (JSON: fwt, cam, hdg×10, pit×10, time-ms)
|
GGS/FWT/<tower>/CamEvent (JSON: fwt, cam, hdg×10, pit×10, time-ms)
|
||||||
GGS/FWT/<tower>/Env (JSON: fwt, temp_c, humid_pct, time-ms)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Local testing
|
## Local testing
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,10 @@ inline constexpr const char* kTopicTargetHdg = "target_HDG";
|
||||||
inline constexpr const char* kTopicControlCode = "ControlCode";
|
inline constexpr const char* kTopicControlCode = "ControlCode";
|
||||||
inline constexpr const char* kTopicStatusCode = "StatusCode";
|
inline constexpr const char* kTopicStatusCode = "StatusCode";
|
||||||
inline constexpr const char* kTopicCamEvent = "CamEvent";
|
inline constexpr const char* kTopicCamEvent = "CamEvent";
|
||||||
inline constexpr const char* kTopicEnv = "Env";
|
|
||||||
|
|
||||||
std::string towerTopic(const std::string& tower, const std::string& leaf);
|
std::string towerTopic(const std::string& tower, const std::string& leaf);
|
||||||
|
|
||||||
// Payload builders. One definition each, used by both channels.
|
// Payload builders. One definition each, used by both channels.
|
||||||
std::string camEventJson(const CamEvent& e);
|
std::string camEventJson(const CamEvent& e);
|
||||||
std::string envJson(const EnvEvent& e);
|
|
||||||
|
|
||||||
} // namespace fgc
|
} // namespace fgc
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,6 @@ struct CamEvent {
|
||||||
long long timestamp_ms = 0; // Unix epoch ms; matches the image filename
|
long long timestamp_ms = 0; // Unix epoch ms; matches the image filename
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ambient temperature/humidity reading published once per fresh sensor sample.
|
|
||||||
struct EnvEvent {
|
|
||||||
std::string tower;
|
|
||||||
float temp_c = 0.0f;
|
|
||||||
float humidity_pct = 0.0f;
|
|
||||||
long long timestamp_ms = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
// What became of an outbound message. Dropped and Failed are separated because
|
// What became of an outbound message. Dropped and Failed are separated because
|
||||||
// they mean different things operationally: Dropped is "the link was down and we
|
// they mean different things operationally: Dropped is "the link was down and we
|
||||||
// discarded it silently", Failed is "the broker or library rejected it".
|
// discarded it silently", Failed is "the broker or library rejected it".
|
||||||
|
|
@ -71,7 +63,6 @@ public:
|
||||||
|
|
||||||
virtual void publishStatus(int code) = 0;
|
virtual void publishStatus(int code) = 0;
|
||||||
virtual void publishCamEvent(const CamEvent& event) = 0;
|
virtual void publishCamEvent(const CamEvent& event) = 0;
|
||||||
virtual void publishEnv(const EnvEvent& event) = 0;
|
|
||||||
|
|
||||||
// Latest control input; clears the *_available flags so each update is
|
// Latest control input; clears the *_available flags so each update is
|
||||||
// acted on once.
|
// acted on once.
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ public:
|
||||||
|
|
||||||
void publishStatus(int code) override;
|
void publishStatus(int code) override;
|
||||||
void publishCamEvent(const CamEvent& event) override;
|
void publishCamEvent(const CamEvent& event) override;
|
||||||
void publishEnv(const EnvEvent& event) override;
|
|
||||||
ControlCommand poll() override;
|
ControlCommand poll() override;
|
||||||
|
|
||||||
std::vector<ChannelMessage> recentMessages() const override { return history_.recent(); }
|
std::vector<ChannelMessage> recentMessages() const override { return history_.recent(); }
|
||||||
|
|
@ -59,7 +58,6 @@ private:
|
||||||
std::string topic_control_code_;
|
std::string topic_control_code_;
|
||||||
std::string topic_status_;
|
std::string topic_status_;
|
||||||
std::string topic_cam_event_;
|
std::string topic_cam_event_;
|
||||||
std::string topic_env_;
|
|
||||||
|
|
||||||
mqtt::async_client client_;
|
mqtt::async_client client_;
|
||||||
mqtt::connect_options conn_opts_;
|
mqtt::connect_options conn_opts_;
|
||||||
|
|
|
||||||
|
|
@ -38,13 +38,6 @@ public:
|
||||||
<< " (null channel)";
|
<< " (null channel)";
|
||||||
drop(kTopicCamEvent, camEventJson(e));
|
drop(kTopicCamEvent, camEventJson(e));
|
||||||
}
|
}
|
||||||
void publishEnv(const EnvEvent& e) override {
|
|
||||||
LOG_TRACE_CAT(LogCat::Mqtt) << "PUB Env temp_c=" << e.temp_c
|
|
||||||
<< " humid_pct=" << e.humidity_pct << " t=" << e.timestamp_ms
|
|
||||||
<< " (null channel)";
|
|
||||||
drop(kTopicEnv, envJson(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
ControlCommand poll() override { return {}; }
|
ControlCommand poll() override { return {}; }
|
||||||
|
|
||||||
std::vector<ChannelMessage> recentMessages() const override { return history_.recent(); }
|
std::vector<ChannelMessage> recentMessages() const override { return history_.recent(); }
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,6 @@ struct Application::Impl {
|
||||||
bool test_drift_gate_ = false;
|
bool test_drift_gate_ = false;
|
||||||
mutable ImuConfigView imu_config_view_; // formatted MTi config (read once)
|
mutable ImuConfigView imu_config_view_; // formatted MTi config (read once)
|
||||||
mutable bool imu_config_done_ = false;
|
mutable bool imu_config_done_ = false;
|
||||||
mutable long long last_env_published_ts_ = 0; // gate MQTT publish to one per fresh sample
|
|
||||||
// Latches the "no IMU sample, publishing encoder pitch" warning so an outage
|
// Latches the "no IMU sample, publishing encoder pitch" warning so an outage
|
||||||
// costs one line, not one per frame. Written from the camera delivery
|
// costs one line, not one per frame. Written from the camera delivery
|
||||||
// thread(s) via the orientation supplier, hence atomic.
|
// thread(s) via the orientation supplier, hence atomic.
|
||||||
|
|
@ -746,16 +745,6 @@ struct Application::Impl {
|
||||||
setField(g.fields[0], fmt1(m->temp_c));
|
setField(g.fields[0], fmt1(m->temp_c));
|
||||||
setField(g.fields[1], fmt1(m->humidity_pct));
|
setField(g.fields[1], fmt1(m->humidity_pct));
|
||||||
}
|
}
|
||||||
// Publish once per fresh sample, not every ~10ms control-loop tick.
|
|
||||||
if (channel && m->timestamp_ms != last_env_published_ts_) {
|
|
||||||
last_env_published_ts_ = m->timestamp_ms;
|
|
||||||
EnvEvent ev;
|
|
||||||
ev.tower = cfg.general.tower_name;
|
|
||||||
ev.temp_c = m->temp_c;
|
|
||||||
ev.humidity_pct = m->humidity_pct;
|
|
||||||
ev.timestamp_ms = m->timestamp_ms;
|
|
||||||
channel->publishEnv(ev);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
s.sensors.env.status = "no fix";
|
s.sensors.env.status = "no fix";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,4 @@ std::string camEventJson(const CamEvent& e) {
|
||||||
", \"time\":" + std::to_string(e.timestamp_ms) + " }";
|
", \"time\":" + std::to_string(e.timestamp_ms) + " }";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string envJson(const EnvEvent& e) {
|
|
||||||
return "{ \"fwt\":\"" + e.tower + "\", \"temp_c\":" + std::to_string(e.temp_c) +
|
|
||||||
", \"humid_pct\":" + std::to_string(e.humidity_pct) +
|
|
||||||
", \"time\":" + std::to_string(e.timestamp_ms) + " }";
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fgc
|
} // namespace fgc
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ MqttControlChannel::MqttControlChannel(const std::string& broker_uri, const std:
|
||||||
topic_control_code_(towerTopic(tower, kTopicControlCode)),
|
topic_control_code_(towerTopic(tower, kTopicControlCode)),
|
||||||
topic_status_(towerTopic(tower, kTopicStatusCode)),
|
topic_status_(towerTopic(tower, kTopicStatusCode)),
|
||||||
topic_cam_event_(towerTopic(tower, kTopicCamEvent)),
|
topic_cam_event_(towerTopic(tower, kTopicCamEvent)),
|
||||||
topic_env_(towerTopic(tower, kTopicEnv)),
|
|
||||||
client_(broker_uri, tower) {
|
client_(broker_uri, tower) {
|
||||||
conn_opts_.set_keep_alive_interval(20);
|
conn_opts_.set_keep_alive_interval(20);
|
||||||
conn_opts_.set_clean_session(true);
|
conn_opts_.set_clean_session(true);
|
||||||
|
|
@ -136,8 +135,4 @@ void MqttControlChannel::publishCamEvent(const CamEvent& e) {
|
||||||
publish(topic_cam_event_, camEventJson(e));
|
publish(topic_cam_event_, camEventJson(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MqttControlChannel::publishEnv(const EnvEvent& e) {
|
|
||||||
publish(topic_env_, envJson(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace fgc
|
} // namespace fgc
|
||||||
|
|
|
||||||
|
|
@ -544,7 +544,7 @@ Element connDetailPanel(const ConnView& v, ScrollState& st) {
|
||||||
struct TopicRow { const char* dir; const char* leaf; };
|
struct TopicRow { const char* dir; const char* leaf; };
|
||||||
static const TopicRow kTopics[] = {
|
static const TopicRow kTopics[] = {
|
||||||
{"sub", kTopicTargetHdg}, {"sub", kTopicControlCode}, {"pub", kTopicStatusCode},
|
{"sub", kTopicTargetHdg}, {"sub", kTopicControlCode}, {"pub", kTopicStatusCode},
|
||||||
{"pub", kTopicCamEvent}, {"pub", kTopicEnv},
|
{"pub", kTopicCamEvent},
|
||||||
};
|
};
|
||||||
for (const auto& t : kTopics) {
|
for (const auto& t : kTopics) {
|
||||||
const ChannelMessage* last = nullptr;
|
const ChannelMessage* last = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -82,11 +82,4 @@ TEST_CASE("topic and payload builders match the documented wire format") {
|
||||||
CHECK(j.find("\"time\":1719312345678") != std::string::npos);
|
CHECK(j.find("\"time\":1719312345678") != std::string::npos);
|
||||||
// The quality gate is gone; nothing should still be publishing a verdict.
|
// The quality gate is gone; nothing should still be publishing a verdict.
|
||||||
CHECK(j.find("degraded") == std::string::npos);
|
CHECK(j.find("degraded") == std::string::npos);
|
||||||
|
|
||||||
EnvEvent e;
|
|
||||||
e.tower = "Tower"; e.temp_c = 21.5f; e.humidity_pct = 48.0f; e.timestamp_ms = 42;
|
|
||||||
const std::string ej = envJson(e);
|
|
||||||
CHECK(ej.find("\"fwt\":\"Tower\"") != std::string::npos);
|
|
||||||
CHECK(ej.find("\"temp_c\":21.5") != std::string::npos);
|
|
||||||
CHECK(ej.find("\"time\":42") != std::string::npos);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ struct FakeChannel : IControlChannel {
|
||||||
bool connected() const override { return true; }
|
bool connected() const override { return true; }
|
||||||
void publishStatus(int c) override { last_status = c; }
|
void publishStatus(int c) override { last_status = c; }
|
||||||
void publishCamEvent(const CamEvent&) override {}
|
void publishCamEvent(const CamEvent&) override {}
|
||||||
void publishEnv(const EnvEvent&) override {}
|
|
||||||
ControlCommand poll() override {
|
ControlCommand poll() override {
|
||||||
ControlCommand c = next;
|
ControlCommand c = next;
|
||||||
next = {};
|
next = {};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue