Change one thing at a time

Find the first evidence.

Never seen means connection. Alive with a reject means payload. Alive with a wrong value means sensor or conversion.

Use this order

  1. Find the device on the developer view.
  2. If it is never seen, check power, Wi-Fi, MQTT credentials, and certificate.
  3. If it is alive, watch the raw tail while publishing once.
  4. If a reject appears, find its reason below and change only that field.

Every stored reject

Message fixes

payload_not_json

The message body isn't valid JSON. Common cause: single quotes instead of double quotes, or a trailing comma.

GardenSpine.h prevents this. Download a clean copy if the helper was edited. Only a custom publisher needs to inspect its JSON punctuation.

missing_field

Your JSON is missing unit. All five fields are required — see the spec.

GardenSpine.h supplies all five fields. Restore the helper if it was edited; custom publishers should compare their output with the five labeled fields on the spec.

device_id_mismatch

The topic says gm-02 but the payload says gm-01. They must match — you probably copied the config from another node.

GardenSpine.h uses one config value in both places. Check SPINE_DEVICE_ID in config.h, then restore the helper if the IDs still differ.

unit_mismatch

You sent unit: "C" but temperature expects celsius. Units are spelled out.

Copy the unit from the registry. Unit names are lowercase contract values, not display abbreviations.

value_type_wrong

value should be a number for temperature, but arrived as text. Drop the quotes.

Pass the sensor number directly to spine.publish(). Do not turn it into text first.

value_out_of_range

1284 °C is outside the plausible range. Raw sensor value instead of a converted one?

Print the raw sensor value and the converted value separately. Confirm the sensor library and conversion formula.

timestamp_unparseable

ts must be ISO 8601 UTC like 2026-08-14T09:32:00Z, or null if your device has no clock. null is fine.

GardenSpine.h sends null and lets the broker stamp arrival time. Restore the helper if a device timestamp appears unexpectedly.

topic_malformed

Topic needs five segments: garden/zone/device-type/device-id/measurement.

GardenSpine.h builds the topic. Check the zone, device type, and device ID in config.h instead of typing a topic.

zone_not_registered

Zone greenhous-1 isn't in the registry — check the spelling, or open a PR to add it.

Copy SPINE_ZONE from the registry into config.h. If the physical location is genuinely new, ask for a registry change.

device_type_not_registered

This device type is not registered. Copy it from your charter configuration.

Copy SPINE_DEVICE_TYPE from the assigned charter. Do not invent a type in config.h.

device_not_registered

This device ID is not registered. Copy it from the credential slip.

Copy the full device ID and MQTT username from the credential slip. Ask an organiser if the device is absent from the registry.

device_registration_mismatch

The topic's zone or device type does not match this device's registry entry.

Use the zone and device type printed in the assigned charter. A valid device ID cannot move to another topic branch without a registry change.

unexpected_field

The payload has a field outside the five-field contract. Remove the extra field.

The canonical payload contains exactly five fields. Restore GardenSpine.h or remove the extra key from a custom publisher.

rate_limited

This device published more than 60 messages in a minute and is being throttled. Slow your loop down.

Publish measurements once per minute while debugging. Check that the publish call is not inside a loop without a delay.

No message at all

Connection checklist

Wi-Fi

Use the open programme network panoulu with an empty password. If the board never receives an IP address, move to the documented organiser hotspot before changing MQTT code.

TLS

The certificate ships inside the library, so there is nothing to paste. A certificate error is not fixed by disabling verification — reinstall the library, then confirm the host is gardenspine.ikapo.fi on port 8883.

Wiring and power

Confirm a common ground. Disconnect the servo and test the sensor alone if the board resets. A charge-only USB cable can power a board without providing a serial port.

Physical reality

The greenhouse changes the diagnosis

Sunlight destroys IR beam readings

Direct sun can saturate an IR receiver. Shade the receiver, shorten the gap, modulate the beam, or move the test indoors before changing the counting code.

Humidity destroys unenclosed electronics

Mount the board above splash level. Cover exposed joins and power rails. Keep sensor vents open; a sealed humidity sensor measures its enclosure.

The ESP32 warms its own sensor

The board can bias a nearby temperature sensor by one or two degrees. Put the sensor on a lead, away from the regulator and trapped enclosure air.