MQTT multiple Numbers with device-based discovery

I am using MQTT device discovery, with several components on one device. This is working well for the Sensor components (which have excellent examples in the documentation), but I’m having trouble with the other platforms, specifically Number and Switch.
Now, all the components are appearing in the Entities list and I can make cards to display them. However, the Numbers and Switches seem to ignore their value_template and put out the raw value to the command_topic rather than JSON. Also, updating the command topic does not update any of the Number values in Home Assistant.

How is this normally done? This suggestion from four years ago suggests that Numbers do not support the value_template field, in which case they would need a separate command_topic for each. But the device-based discovery seems to only support a single command_topic (much like the single state_topic).

Here is my complete configuration payload:

{
	"dev":	{
		"mf":	"Espressif",
		"mdl":	"ESP-WROOM32",
		"sw":	"v5.4.1-dirty",
		"ids":	"94B97EE9B9E8",
		"hw":	"ESP32 v1.0",
		"name":	"seedlings"
	},
	"o":	{
		"name":	"ESP32 MQTT Sensor",
		"sw":	"0.1.2",
		"url":	"https://github.com/kamocat/esp32_sensor"
	},
	"cmps":	{
		"94B97EE9B9E8_cmp1":	{
			"unique_id":	"94B97EE9B9E8_cmp1",
			"p":	"sensor",
			"name":	"moisture",
			"unit_of_measurement":	"in",
			"value_template":	"{{ value_json.moisture}}"
		},
		"94B97EE9B9E8_cmp2":	{
			"unique_id":	"94B97EE9B9E8_cmp2",
			"p":	"sensor",
			"name":	"rssi",
			"value_template":	"{{ value_json.rssi}}"
		},
		"94B97EE9B9E8_cmp3":	{
			"unique_id":	"94B97EE9B9E8_cmp3",
			"p":	"sensor",
			"name":	"free_mem",
			"unit_of_measurement":	"bytes",
			"value_template":	"{{ value_json.free_mem}}"
		},
		"94B97EE9B9E8_cmp4":	{
			"unique_id":	"94B97EE9B9E8_cmp4",
			"p":	"binary_sensor",
			"name":	"pump_on",
			"value_template":	"{{ value_json.pump_on}}"
		},
		"94B97EE9B9E8_cmp5":	{
			"unique_id":	"94B97EE9B9E8_cmp5",
			"p":	"switch",
			"name":	"pump_enabled",
			"value_template":	"{{ value_json.pump_enabled}}"
		},
		"94B97EE9B9E8_cmp6":	{
			"unique_id":	"94B97EE9B9E8_cmp6",
			"p":	"number",
			"name":	"update_period",
			"unit_of_measurement":	"s",
			"value_template":	"{{ value_json.update_period}}",
			"command_template":	"{ \"update_period\": {{value | round(3)}} }",
			"qos":	1,
			"retain":	true,
			"min":	1,
			"max":	1800,
			"step":	1
		},
		"94B97EE9B9E8_cmp7":	{
			"unique_id":	"94B97EE9B9E8_cmp7",
			"p":	"number",
			"name":	"pump_timeout",
			"unit_of_measurement":	"s",
			"value_template":	"{{ value_json.pump_timeout}}",
			"command_template":	"{ \"pump_timeout\": {{value | round(3)}} }",
			"qos":	1,
			"retain":	true,
			"min":	1,
			"max":	300,
			"step":	1
		},
		"94B97EE9B9E8_cmp8":	{
			"unique_id":	"94B97EE9B9E8_cmp8",
			"p":	"number",
			"name":	"min_threshold",
			"unit_of_measurement":	"in",
			"value_template":	"{{ value_json.min_threshold}}",
			"command_template":	"{ \"min_threshold\": {{value | round(3)}} }",
			"qos":	1,
			"retain":	true,
			"min":	0,
			"max":	10,
			"step":	0.0010000000474974513
		},
		"94B97EE9B9E8_cmp9":	{
			"unique_id":	"94B97EE9B9E8_cmp9",
			"p":	"number",
			"name":	"max_threshold",
			"unit_of_measurement":	"in",
			"value_template":	"{{ value_json.max_threshold}}",
			"command_template":	"{ \"max_threshold\": {{value | round(3)}} }",
			"qos":	1,
			"retain":	true,
			"min":	0,
			"max":	10,
			"step":	0.0010000000474974513
		},
		"94B97EE9B9E8_cmp10":	{
			"unique_id":	"94B97EE9B9E8_cmp10",
			"p":	"number",
			"name":	"voltage",
			"unit_of_measurement":	"V",
			"value_template":	"{{ value_json.voltage}}",
			"command_template":	"{ \"voltage\": {{value | round(3)}} }",
			"qos":	1,
			"retain":	true,
			"min":	0,
			"max":	10,
			"step":	0.0010000000474974513
		}
	},
	"qos":	2,
	"state_topic":	"garden/seedlings/state",
	"command_topic":	"garden/seedlings/cfg"
}

It looks like I may have missed a note in the Templating documentation.
Apparently json_value is used for incoming data but value is used for outgoing data?

Accordingly, I have added a command_template in the form "{ \"XXXX\": {{value | round(3)}} }" and now the data is being sent correctly.

I have yet to address the boolean values. I was expecting true and false rather than the ON, OFF, and UNKNOWN that seem to be the norm here.
Is this something that can be converted with templating, or do I need to modify the cJSON library on the embedded side to support this new trinary datatype?

I’m leaving these links here for me to come back to:
binary_sensor.mqtt
switch.mqtt

I think the iif operator is what I need to convert ON into true
jinja immidiate if

EDIT:
It works, so long as I remember to close the parentheses. Here’s what I did:
"value_template": "{{ iif(value_json.pump_enabled,'ON','OFF')}}", "command_template": "{ \"pump_enabled\": {{iif(is_state(value,'ON'), 'true','false')}} }"