I bought a cheap(ish) weather sensor from Amazon ( Official 2026 UK Version, with 3 x Wireless Sensors Weather Station, Radio Controlled Clock Indoor Outdoor Temperature Thermometer, Humidity, Barometric Pressure : Amazon.co.uk: Garden ) and have used the following hardware to integrate it into HomeAssistant.
I then use this code is ESPHOME to capture all the radio traffic so I could get the SensorID and model id for all 3 sensors
Sorry for the basic info - but I hope it will get someone started ( as it took a fair amount or trial and error to get it working )
####### Use this to get the platform / Sensor ID ##########
esphome:
name: esphome-web-c4a1a8
friendly_name: Weather Station
name_add_mac_suffix: false
comment: "ESP32 + CC1101 receiver for Youshiko YC9443 wireless weather sensors"
esp32:
board: esp32dev
framework:
type: arduino
# type: esp-idf
advanced:
minimum_chip_revision: "3.1"
sram1_as_iram: true
logger:
level: INFO
#level: VERY_VERBOSE
logs:
# Keep RF decoding visible but avoid making Wi-Fi/API too noisy.
rtl_433: INFO
remote_receiver: INFO
cc1101: INFO
# rtl_433: VERY_VERBOSE
# remote_receiver: VERY_VERBOSE
# cc1101: VERY_VERBOSE
api:
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
min_auth_mode: WPA2
# Prevent reboot loops if Wi-Fi fails
reboot_timeout: 0s
web_server:
port: 80
version: 3
local: true
substitutions:
device_name: youshiko_yc9443_rf
friendly_name: "Youshiko YC9443 RF"
# ESP32 board type. Common values:
# esp32dev, nodemcu-32s, esp32doit-devkit-v1, lolin_s2_mini, etc.
esp32_board: esp32dev
# CC1101 SPI pins.
# These are common ESP32 VSPI defaults, but use YOUR actual wiring.
pin_sck: GPIO18
pin_mosi: GPIO23
pin_miso: GPIO19
pin_cs: GPIO5
# CC1101 data output pin.
# For receive-only, connect CC1101 GDO2 to this GPIO if available.
# If your module only has GDO0 wired, set this to your GDO0 GPIO.
# pin_cc1101_rx: GPIO32
pin_cc1101_rx: GPIO4
# Normal UK/EU weather sensors are usually 433.92 MHz.
# If your raw logs are strongest elsewhere, tune this slightly.
rf_frequency: 433.92MHz
# Community rtl_433 decoder for ESPHome.
# It receives pulses from ESPHome remote_receiver and tries rtl_433 protocol decoders.
packages:
rtl_433: github://juanboro/esphome-rtl_433-decoder/rtl_433.yaml
# SPI bus used by the CC1101.
spi:
clk_pin: ${pin_sck}
mosi_pin: ${pin_mosi}
miso_pin: ${pin_miso}
# Native ESPHome CC1101 driver.
# ASK/OOK is the usual modulation for simple 433 MHz weather sensors.
cc1101:
id: cc1101_radio
cs_pin: ${pin_cs}
frequency: ${rf_frequency}
modulation_type: ASK/OOK
# Conservative starting values. Adjust only if reception is unreliable.
symbol_rate: 5000
filter_bandwidth: 203kHz
rx_attenuation: 0dB
# Pulse receiver fed from the CC1101 GDO output.
# This creates the pulse stream consumed by rtl_433.
remote_receiver:
id: rf_receiver
pin:
number: ${pin_cc1101_rx}
mode:
input: true
pullup: false
# Weather sensors transmit short bursts every 30-90 seconds.
# idle controls where one RF burst is considered complete.
idle: 10ms
# Ignore very short noise pulses.
filter: 20us
# Large enough for weather-station messages.
buffer_size: 4096
# During discovery this is useful. After things work, change to:
#dump: []
dump: all
# rtl_433 decoder connected to the ESPHome remote_receiver above.
rtl_433:
id: rtl433_decoder
receiver_id: rf_receiver
on_json_message:
then:
- lambda: |-
// Discovery logger: print every decoded rtl_433 message.
std::string msg;
serializeJson(x, msg);
ESP_LOGI("rtl_433", "decoded: %s", msg.c_str());
const char *model = x["model"] | "";
int sensor_id = x["id"] | -1;
int channel = x["channel"] | -1;
bool has_temp = x["temperature_C"].is<float>() || x["temperature_C"].is<int>();
bool has_humidity = x["humidity"].is<float>() || x["humidity"].is<int>();
ESP_LOGI(
"rtl_433",
"summary: model=%s id=%d channel=%d has_temp=%s has_humidity=%s",
model,
sensor_id,
channel,
has_temp ? "yes" : "no",
has_humidity ? "yes" : "no"
);
time:
- platform: sntp
id: sntp_time
timezone: Europe/London
sensor:
# Channel 1
- platform: template
name: "Youshiko Channel 1 Temperature"
id: youshiko_ch1_temperature
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "Youshiko Channel 1 Humidity"
id: youshiko_ch1_humidity
unit_of_measurement: "%"
device_class: humidity
state_class: measurement
accuracy_decimals: 0
# Channel 2
- platform: template
name: "Youshiko Channel 2 Temperature"
id: youshiko_ch2_temperature
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "Youshiko Channel 2 Humidity"
id: youshiko_ch2_humidity
unit_of_measurement: "%"
device_class: humidity
state_class: measurement
accuracy_decimals: 0
# Channel 3
- platform: template
name: "Youshiko Channel 3 Temperature"
id: youshiko_ch3_temperature
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "Youshiko Channel 3 Humidity"
id: youshiko_ch3_humidity
unit_of_measurement: "%"
device_class: humidity
state_class: measurement
accuracy_decimals: 0
binary_sensor:
- platform: template
name: "Youshiko Channel 1 Battery OK"
id: youshiko_ch1_battery_ok
device_class: battery
- platform: template
name: "Youshiko Channel 2 Battery OK"
id: youshiko_ch2_battery_ok
device_class: battery
- platform: template
name: "Youshiko Channel 3 Battery OK"
id: youshiko_ch3_battery_ok
device_class: battery
text_sensor:
- platform: template
name: "Youshiko Channel 1 Last Seen"
id: youshiko_ch1_last_seen
- platform: template
name: "Youshiko Channel 2 Last Seen"
id: youshiko_ch2_last_seen
- platform: template
name: "Youshiko Channel 3 Last Seen"
id: youshiko_ch3_last_seen
Then once I had the correct Sensor and Device ID I updated the rtl_433 section in the Final Code below and that fully integrated it into Home Assistant.
esphome:
name: esphome-web-c4a1a8
friendly_name: Weather Station
name_add_mac_suffix: false
comment: "ESP32 + CC1101 receiver for Youshiko YC9443 wireless weather sensors"
esp32:
board: esp32dev
framework:
type: arduino
# type: esp-idf
advanced:
minimum_chip_revision: "3.1"
sram1_as_iram: true
logger:
level: INFO
#level: VERY_VERBOSE
logs:
# Keep RF decoding visible but avoid making Wi-Fi/API too noisy.
rtl_433: INFO
remote_receiver: WARN
cc1101: WARN
# rtl_433: VERY_VERBOSE
# remote_receiver: VERY_VERBOSE
# cc1101: VERY_VERBOSE
api:
ota:
- platform: esphome
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
min_auth_mode: WPA2
# Prevent reboot loops if Wi-Fi fails
reboot_timeout: 0s
web_server:
port: 80
version: 3
local: true
substitutions:
device_name: youshiko_yc9443_rf
friendly_name: "Youshiko YC9443 RF"
# CC1101 SPI pins.
# These are common ESP32 VSPI defaults, but use YOUR actual wiring.
pin_sck: GPIO18
pin_mosi: GPIO23
pin_miso: GPIO19
pin_cs: GPIO5
# CC1101 data output pin.
# For receive-only, connect CC1101 GDO2 to this GPIO if available.
# If your module only has GDO0 wired, set this to your GDO0 GPIO.
# pin_cc1101_rx: GPIO32
pin_cc1101_rx: GPIO4
# Normal UK/EU weather sensors are usually 433.92 MHz.
# If your raw logs are strongest elsewhere, tune this slightly.
rf_frequency: 433.92MHz
# Community rtl_433 decoder for ESPHome.
# It receives pulses from ESPHome remote_receiver and tries rtl_433 protocol decoders.
packages:
rtl_433: github://juanboro/esphome-rtl_433-decoder/rtl_433.yaml
# SPI bus used by the CC1101.
spi:
clk_pin: ${pin_sck}
mosi_pin: ${pin_mosi}
miso_pin: ${pin_miso}
# Native ESPHome CC1101 driver.
# ASK/OOK is the usual modulation for simple 433 MHz weather sensors.
cc1101:
id: cc1101_radio
cs_pin: ${pin_cs}
frequency: ${rf_frequency}
modulation_type: ASK/OOK
# Conservative starting values. Adjust only if reception is unreliable.
symbol_rate: 5000
filter_bandwidth: 203kHz
rx_attenuation: 0dB
# Pulse receiver fed from the CC1101 GDO output.
# This creates the pulse stream consumed by rtl_433.
remote_receiver:
id: rf_receiver
pin:
number: ${pin_cc1101_rx}
mode:
input: true
pullup: false
# Weather sensors transmit short bursts every 30-90 seconds.
# idle controls where one RF burst is considered complete.
idle: 10ms
# Ignore very short noise pulses.
filter: 20us
# Large enough for weather-station messages.
buffer_size: 4096
# During discovery this is useful. After things work, change to:
dump: []
#dump: all
# rtl_433 decoder connected to the ESPHome remote_receiver above.
rtl_433:
id: rtl433_decoder
receiver_id: rf_receiver
on_json_message:
then:
- lambda: |-
const char *model = x["model"] | "";
int sensor_id = x["id"] | -1;
int channel = x["channel"] | -1;
// Ignore anything that is not one of the Youshiko / inFactory-compatible sensors.
if (strcmp(model, "inFactory-TH") != 0) {
return;
}
bool has_temp = x["temperature_C"].is<float>() || x["temperature_C"].is<int>();
bool has_humidity = x["humidity"].is<float>() || x["humidity"].is<int>();
bool has_battery = x["battery_ok"].is<int>() || x["battery_ok"].is<bool>();
// Channel 1: id 227
if (sensor_id == 227 && channel == 1) {
if (has_temp) {
id(youshiko_ch1_temperature).publish_state(x["temperature_C"].as<float>());
}
if (has_humidity) {
id(youshiko_ch1_humidity).publish_state(x["humidity"].as<float>());
}
if (has_battery) {
id(youshiko_ch1_battery_ok).publish_state(x["battery_ok"].as<int>() > 0);
}
if (id(sntp_time).now().is_valid()) {
id(youshiko_ch1_last_seen).publish_state(
id(sntp_time).now().strftime("%Y-%m-%d %H:%M:%S")
);
}
ESP_LOGI("rtl_433", "Youshiko CH1 updated: id=227");
}
// Channel 2: id 183
else if (sensor_id == 183 && channel == 2) {
if (has_temp) {
id(youshiko_ch2_temperature).publish_state(x["temperature_C"].as<float>());
}
if (has_humidity) {
id(youshiko_ch2_humidity).publish_state(x["humidity"].as<float>());
}
if (has_battery) {
id(youshiko_ch2_battery_ok).publish_state(x["battery_ok"].as<int>() > 0);
}
if (id(sntp_time).now().is_valid()) {
id(youshiko_ch2_last_seen).publish_state(
id(sntp_time).now().strftime("%Y-%m-%d %H:%M:%S")
);
}
ESP_LOGI("rtl_433", "Youshiko CH2 updated: id=183");
}
// Channel 3: id 152
else if (sensor_id == 152 && channel == 3) {
if (has_temp) {
id(youshiko_ch3_temperature).publish_state(x["temperature_C"].as<float>());
}
if (has_humidity) {
id(youshiko_ch3_humidity).publish_state(x["humidity"].as<float>());
}
if (has_battery) {
id(youshiko_ch3_battery_ok).publish_state(x["battery_ok"].as<int>() > 0);
}
if (id(sntp_time).now().is_valid()) {
id(youshiko_ch3_last_seen).publish_state(
id(sntp_time).now().strftime("%Y-%m-%d %H:%M:%S")
);
}
ESP_LOGI("rtl_433", "Youshiko CH3 updated: id=152");
}
time:
- platform: sntp
id: sntp_time
timezone: Europe/London
sensor:
# Channel 1
- platform: template
name: "Youshiko Channel 1 Temperature"
id: youshiko_ch1_temperature
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "Youshiko Channel 1 Humidity"
id: youshiko_ch1_humidity
unit_of_measurement: "%"
device_class: humidity
state_class: measurement
accuracy_decimals: 0
# Channel 2
- platform: template
name: "Youshiko Channel 2 Temperature"
id: youshiko_ch2_temperature
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "Youshiko Channel 2 Humidity"
id: youshiko_ch2_humidity
unit_of_measurement: "%"
device_class: humidity
state_class: measurement
accuracy_decimals: 0
# Channel 3
- platform: template
name: "Youshiko Channel 3 Temperature"
id: youshiko_ch3_temperature
unit_of_measurement: "°C"
device_class: temperature
state_class: measurement
accuracy_decimals: 1
- platform: template
name: "Youshiko Channel 3 Humidity"
id: youshiko_ch3_humidity
unit_of_measurement: "%"
device_class: humidity
state_class: measurement
accuracy_decimals: 0
binary_sensor:
- platform: template
name: "Youshiko Channel 1 Battery OK"
id: youshiko_ch1_battery_ok
device_class: battery
- platform: template
name: "Youshiko Channel 2 Battery OK"
id: youshiko_ch2_battery_ok
device_class: battery
- platform: template
name: "Youshiko Channel 3 Battery OK"
id: youshiko_ch3_battery_ok
device_class: battery
text_sensor:
- platform: template
name: "Youshiko Channel 1 Last Seen"
id: youshiko_ch1_last_seen
- platform: template
name: "Youshiko Channel 2 Last Seen"
id: youshiko_ch2_last_seen
- platform: template
name: "Youshiko Channel 3 Last Seen"
id: youshiko_ch3_last_seen