mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 15:12:06 +00:00 
			
		
		
		
	[sx127x] Add sx127x component (#7490)
Co-authored-by: Jonathan Swoboda <jonathan.swoboda>
This commit is contained in:
		| @@ -441,6 +441,7 @@ esphome/components/sun/* @OttoWinter | |||||||
| esphome/components/sun_gtil2/* @Mat931 | esphome/components/sun_gtil2/* @Mat931 | ||||||
| esphome/components/switch/* @esphome/core | esphome/components/switch/* @esphome/core | ||||||
| esphome/components/switch/binary_sensor/* @ssieb | esphome/components/switch/binary_sensor/* @ssieb | ||||||
|  | esphome/components/sx127x/* @swoboda1337 | ||||||
| esphome/components/syslog/* @clydebarrow | esphome/components/syslog/* @clydebarrow | ||||||
| esphome/components/t6615/* @tylermenezes | esphome/components/t6615/* @tylermenezes | ||||||
| esphome/components/tc74/* @sethgirvan | esphome/components/tc74/* @sethgirvan | ||||||
|   | |||||||
							
								
								
									
										325
									
								
								esphome/components/sx127x/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										325
									
								
								esphome/components/sx127x/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,325 @@ | |||||||
|  | from esphome import automation, pins | ||||||
|  | import esphome.codegen as cg | ||||||
|  | from esphome.components import spi | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.const import CONF_DATA, CONF_FREQUENCY, CONF_ID | ||||||
|  |  | ||||||
|  | MULTI_CONF = True | ||||||
|  | CODEOWNERS = ["@swoboda1337"] | ||||||
|  | DEPENDENCIES = ["spi"] | ||||||
|  |  | ||||||
|  | CONF_SX127X_ID = "sx127x_id" | ||||||
|  |  | ||||||
|  | CONF_AUTO_CAL = "auto_cal" | ||||||
|  | CONF_BANDWIDTH = "bandwidth" | ||||||
|  | CONF_BITRATE = "bitrate" | ||||||
|  | CONF_BITSYNC = "bitsync" | ||||||
|  | CONF_CODING_RATE = "coding_rate" | ||||||
|  | CONF_CRC_ENABLE = "crc_enable" | ||||||
|  | CONF_DEVIATION = "deviation" | ||||||
|  | CONF_DIO0_PIN = "dio0_pin" | ||||||
|  | CONF_MODULATION = "modulation" | ||||||
|  | CONF_ON_PACKET = "on_packet" | ||||||
|  | CONF_PA_PIN = "pa_pin" | ||||||
|  | CONF_PA_POWER = "pa_power" | ||||||
|  | CONF_PA_RAMP = "pa_ramp" | ||||||
|  | CONF_PACKET_MODE = "packet_mode" | ||||||
|  | CONF_PAYLOAD_LENGTH = "payload_length" | ||||||
|  | CONF_PREAMBLE_DETECT = "preamble_detect" | ||||||
|  | CONF_PREAMBLE_ERRORS = "preamble_errors" | ||||||
|  | CONF_PREAMBLE_POLARITY = "preamble_polarity" | ||||||
|  | CONF_PREAMBLE_SIZE = "preamble_size" | ||||||
|  | CONF_RST_PIN = "rst_pin" | ||||||
|  | CONF_RX_FLOOR = "rx_floor" | ||||||
|  | CONF_RX_START = "rx_start" | ||||||
|  | CONF_SHAPING = "shaping" | ||||||
|  | CONF_SPREADING_FACTOR = "spreading_factor" | ||||||
|  | CONF_SYNC_VALUE = "sync_value" | ||||||
|  |  | ||||||
|  | sx127x_ns = cg.esphome_ns.namespace("sx127x") | ||||||
|  | SX127x = sx127x_ns.class_("SX127x", cg.Component, spi.SPIDevice) | ||||||
|  | SX127xListener = sx127x_ns.class_("SX127xListener") | ||||||
|  | SX127xBw = sx127x_ns.enum("SX127xBw") | ||||||
|  | SX127xOpMode = sx127x_ns.enum("SX127xOpMode") | ||||||
|  | SX127xPaConfig = sx127x_ns.enum("SX127xPaConfig") | ||||||
|  | SX127xPaRamp = sx127x_ns.enum("SX127xPaRamp") | ||||||
|  | SX127xModemCfg1 = sx127x_ns.enum("SX127xModemCfg1") | ||||||
|  |  | ||||||
|  | BW = { | ||||||
|  |     "2_6kHz": SX127xBw.SX127X_BW_2_6, | ||||||
|  |     "3_1kHz": SX127xBw.SX127X_BW_3_1, | ||||||
|  |     "3_9kHz": SX127xBw.SX127X_BW_3_9, | ||||||
|  |     "5_2kHz": SX127xBw.SX127X_BW_5_2, | ||||||
|  |     "6_3kHz": SX127xBw.SX127X_BW_6_3, | ||||||
|  |     "7_8kHz": SX127xBw.SX127X_BW_7_8, | ||||||
|  |     "10_4kHz": SX127xBw.SX127X_BW_10_4, | ||||||
|  |     "12_5kHz": SX127xBw.SX127X_BW_12_5, | ||||||
|  |     "15_6kHz": SX127xBw.SX127X_BW_15_6, | ||||||
|  |     "20_8kHz": SX127xBw.SX127X_BW_20_8, | ||||||
|  |     "25_0kHz": SX127xBw.SX127X_BW_25_0, | ||||||
|  |     "31_3kHz": SX127xBw.SX127X_BW_31_3, | ||||||
|  |     "41_7kHz": SX127xBw.SX127X_BW_41_7, | ||||||
|  |     "50_0kHz": SX127xBw.SX127X_BW_50_0, | ||||||
|  |     "62_5kHz": SX127xBw.SX127X_BW_62_5, | ||||||
|  |     "83_3kHz": SX127xBw.SX127X_BW_83_3, | ||||||
|  |     "100_0kHz": SX127xBw.SX127X_BW_100_0, | ||||||
|  |     "125_0kHz": SX127xBw.SX127X_BW_125_0, | ||||||
|  |     "166_7kHz": SX127xBw.SX127X_BW_166_7, | ||||||
|  |     "200_0kHz": SX127xBw.SX127X_BW_200_0, | ||||||
|  |     "250_0kHz": SX127xBw.SX127X_BW_250_0, | ||||||
|  |     "500_0kHz": SX127xBw.SX127X_BW_500_0, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | CODING_RATE = { | ||||||
|  |     "CR_4_5": SX127xModemCfg1.CODING_RATE_4_5, | ||||||
|  |     "CR_4_6": SX127xModemCfg1.CODING_RATE_4_6, | ||||||
|  |     "CR_4_7": SX127xModemCfg1.CODING_RATE_4_7, | ||||||
|  |     "CR_4_8": SX127xModemCfg1.CODING_RATE_4_8, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MOD = { | ||||||
|  |     "LORA": SX127xOpMode.MOD_LORA, | ||||||
|  |     "FSK": SX127xOpMode.MOD_FSK, | ||||||
|  |     "OOK": SX127xOpMode.MOD_OOK, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | PA_PIN = { | ||||||
|  |     "RFO": SX127xPaConfig.PA_PIN_RFO, | ||||||
|  |     "BOOST": SX127xPaConfig.PA_PIN_BOOST, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | RAMP = { | ||||||
|  |     "10us": SX127xPaRamp.PA_RAMP_10, | ||||||
|  |     "12us": SX127xPaRamp.PA_RAMP_12, | ||||||
|  |     "15us": SX127xPaRamp.PA_RAMP_15, | ||||||
|  |     "20us": SX127xPaRamp.PA_RAMP_20, | ||||||
|  |     "25us": SX127xPaRamp.PA_RAMP_25, | ||||||
|  |     "31us": SX127xPaRamp.PA_RAMP_31, | ||||||
|  |     "40us": SX127xPaRamp.PA_RAMP_40, | ||||||
|  |     "50us": SX127xPaRamp.PA_RAMP_50, | ||||||
|  |     "62us": SX127xPaRamp.PA_RAMP_62, | ||||||
|  |     "100us": SX127xPaRamp.PA_RAMP_100, | ||||||
|  |     "125us": SX127xPaRamp.PA_RAMP_125, | ||||||
|  |     "250us": SX127xPaRamp.PA_RAMP_250, | ||||||
|  |     "500us": SX127xPaRamp.PA_RAMP_500, | ||||||
|  |     "1000us": SX127xPaRamp.PA_RAMP_1000, | ||||||
|  |     "2000us": SX127xPaRamp.PA_RAMP_2000, | ||||||
|  |     "3400us": SX127xPaRamp.PA_RAMP_3400, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SHAPING = { | ||||||
|  |     "CUTOFF_BR_X_2": SX127xPaRamp.CUTOFF_BR_X_2, | ||||||
|  |     "CUTOFF_BR_X_1": SX127xPaRamp.CUTOFF_BR_X_1, | ||||||
|  |     "GAUSSIAN_BT_0_3": SX127xPaRamp.GAUSSIAN_BT_0_3, | ||||||
|  |     "GAUSSIAN_BT_0_5": SX127xPaRamp.GAUSSIAN_BT_0_5, | ||||||
|  |     "GAUSSIAN_BT_1_0": SX127xPaRamp.GAUSSIAN_BT_1_0, | ||||||
|  |     "NONE": SX127xPaRamp.SHAPING_NONE, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | RunImageCalAction = sx127x_ns.class_( | ||||||
|  |     "RunImageCalAction", automation.Action, cg.Parented.template(SX127x) | ||||||
|  | ) | ||||||
|  | SendPacketAction = sx127x_ns.class_( | ||||||
|  |     "SendPacketAction", automation.Action, cg.Parented.template(SX127x) | ||||||
|  | ) | ||||||
|  | SetModeTxAction = sx127x_ns.class_( | ||||||
|  |     "SetModeTxAction", automation.Action, cg.Parented.template(SX127x) | ||||||
|  | ) | ||||||
|  | SetModeRxAction = sx127x_ns.class_( | ||||||
|  |     "SetModeRxAction", automation.Action, cg.Parented.template(SX127x) | ||||||
|  | ) | ||||||
|  | SetModeSleepAction = sx127x_ns.class_( | ||||||
|  |     "SetModeSleepAction", automation.Action, cg.Parented.template(SX127x) | ||||||
|  | ) | ||||||
|  | SetModeStandbyAction = sx127x_ns.class_( | ||||||
|  |     "SetModeStandbyAction", automation.Action, cg.Parented.template(SX127x) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def validate_raw_data(value): | ||||||
|  |     if isinstance(value, str): | ||||||
|  |         return value.encode("utf-8") | ||||||
|  |     if isinstance(value, list): | ||||||
|  |         return cv.Schema([cv.hex_uint8_t])(value) | ||||||
|  |     raise cv.Invalid( | ||||||
|  |         "data must either be a string wrapped in quotes or a list of bytes" | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def validate_config(config): | ||||||
|  |     if config[CONF_MODULATION] == "LORA": | ||||||
|  |         bws = [ | ||||||
|  |             "7_8kHz", | ||||||
|  |             "10_4kHz", | ||||||
|  |             "15_6kHz", | ||||||
|  |             "20_8kHz", | ||||||
|  |             "31_3kHz", | ||||||
|  |             "41_7kHz", | ||||||
|  |             "62_5kHz", | ||||||
|  |             "125_0kHz", | ||||||
|  |             "250_0kHz", | ||||||
|  |             "500_0kHz", | ||||||
|  |         ] | ||||||
|  |         if config[CONF_BANDWIDTH] not in bws: | ||||||
|  |             raise cv.Invalid(f"{config[CONF_BANDWIDTH]} is not available with LORA") | ||||||
|  |         if CONF_DIO0_PIN not in config: | ||||||
|  |             raise cv.Invalid("Cannot use LoRa without dio0_pin") | ||||||
|  |         if 0 < config[CONF_PREAMBLE_SIZE] < 6: | ||||||
|  |             raise cv.Invalid("Minimum preamble size is 6 with LORA") | ||||||
|  |         if config[CONF_SPREADING_FACTOR] == 6 and config[CONF_PAYLOAD_LENGTH] == 0: | ||||||
|  |             raise cv.Invalid("Payload length must be set when spreading factor is 6") | ||||||
|  |     else: | ||||||
|  |         if config[CONF_BANDWIDTH] == "500_0kHz": | ||||||
|  |             raise cv.Invalid(f"{config[CONF_BANDWIDTH]} is only available with LORA") | ||||||
|  |         if CONF_BITSYNC not in config: | ||||||
|  |             raise cv.Invalid("Config 'bitsync' required with FSK/OOK") | ||||||
|  |         if CONF_PACKET_MODE not in config: | ||||||
|  |             raise cv.Invalid("Config 'packet_mode' required with FSK/OOK") | ||||||
|  |         if config[CONF_PACKET_MODE] and CONF_DIO0_PIN not in config: | ||||||
|  |             raise cv.Invalid("Config 'dio0_pin' required in packet mode") | ||||||
|  |         if config[CONF_PAYLOAD_LENGTH] > 64: | ||||||
|  |             raise cv.Invalid("Payload length must be <= 64 with FSK/OOK") | ||||||
|  |     if config[CONF_PA_PIN] == "RFO" and config[CONF_PA_POWER] > 15: | ||||||
|  |         raise cv.Invalid("PA power must be <= 15 dbm when using the RFO pin") | ||||||
|  |     if config[CONF_PA_PIN] == "BOOST" and config[CONF_PA_POWER] < 2: | ||||||
|  |         raise cv.Invalid("PA power must be >= 2 dbm when using the BOOST pin") | ||||||
|  |     return config | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = ( | ||||||
|  |     cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(SX127x), | ||||||
|  |             cv.Optional(CONF_AUTO_CAL, default=True): cv.boolean, | ||||||
|  |             cv.Optional(CONF_BANDWIDTH, default="125_0kHz"): cv.enum(BW), | ||||||
|  |             cv.Optional(CONF_BITRATE, default=4800): cv.int_range(min=500, max=300000), | ||||||
|  |             cv.Optional(CONF_BITSYNC): cv.boolean, | ||||||
|  |             cv.Optional(CONF_CODING_RATE, default="CR_4_5"): cv.enum(CODING_RATE), | ||||||
|  |             cv.Optional(CONF_CRC_ENABLE, default=False): cv.boolean, | ||||||
|  |             cv.Optional(CONF_DEVIATION, default=5000): cv.int_range(min=0, max=100000), | ||||||
|  |             cv.Optional(CONF_DIO0_PIN): pins.internal_gpio_input_pin_schema, | ||||||
|  |             cv.Required(CONF_FREQUENCY): cv.int_range(min=137000000, max=1020000000), | ||||||
|  |             cv.Required(CONF_MODULATION): cv.enum(MOD), | ||||||
|  |             cv.Optional(CONF_ON_PACKET): automation.validate_automation(single=True), | ||||||
|  |             cv.Optional(CONF_PA_PIN, default="BOOST"): cv.enum(PA_PIN), | ||||||
|  |             cv.Optional(CONF_PA_POWER, default=17): cv.int_range(min=0, max=17), | ||||||
|  |             cv.Optional(CONF_PA_RAMP, default="40us"): cv.enum(RAMP), | ||||||
|  |             cv.Optional(CONF_PACKET_MODE): cv.boolean, | ||||||
|  |             cv.Optional(CONF_PAYLOAD_LENGTH, default=0): cv.int_range(min=0, max=256), | ||||||
|  |             cv.Optional(CONF_PREAMBLE_DETECT, default=0): cv.int_range(min=0, max=3), | ||||||
|  |             cv.Optional(CONF_PREAMBLE_ERRORS, default=0): cv.int_range(min=0, max=31), | ||||||
|  |             cv.Optional(CONF_PREAMBLE_POLARITY, default=0xAA): cv.All( | ||||||
|  |                 cv.hex_int, cv.one_of(0xAA, 0x55) | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_PREAMBLE_SIZE, default=0): cv.int_range(min=0, max=65535), | ||||||
|  |             cv.Required(CONF_RST_PIN): pins.internal_gpio_output_pin_schema, | ||||||
|  |             cv.Optional(CONF_RX_FLOOR, default=-94): cv.float_range(min=-128, max=-1), | ||||||
|  |             cv.Optional(CONF_RX_START, default=True): cv.boolean, | ||||||
|  |             cv.Optional(CONF_SHAPING, default="NONE"): cv.enum(SHAPING), | ||||||
|  |             cv.Optional(CONF_SPREADING_FACTOR, default=7): cv.int_range(min=6, max=12), | ||||||
|  |             cv.Optional(CONF_SYNC_VALUE, default=[]): cv.ensure_list(cv.hex_uint8_t), | ||||||
|  |         }, | ||||||
|  |     ) | ||||||
|  |     .extend(cv.COMPONENT_SCHEMA) | ||||||
|  |     .extend(spi.spi_device_schema(True, 8e6, "mode0")) | ||||||
|  |     .add_extra(validate_config) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |     await spi.register_spi_device(var, config) | ||||||
|  |     if CONF_ON_PACKET in config: | ||||||
|  |         await automation.build_automation( | ||||||
|  |             var.get_packet_trigger(), | ||||||
|  |             [ | ||||||
|  |                 (cg.std_vector.template(cg.uint8), "x"), | ||||||
|  |                 (cg.float_, "rssi"), | ||||||
|  |                 (cg.float_, "snr"), | ||||||
|  |             ], | ||||||
|  |             config[CONF_ON_PACKET], | ||||||
|  |         ) | ||||||
|  |     if CONF_DIO0_PIN in config: | ||||||
|  |         dio0_pin = await cg.gpio_pin_expression(config[CONF_DIO0_PIN]) | ||||||
|  |         cg.add(var.set_dio0_pin(dio0_pin)) | ||||||
|  |     rst_pin = await cg.gpio_pin_expression(config[CONF_RST_PIN]) | ||||||
|  |     cg.add(var.set_rst_pin(rst_pin)) | ||||||
|  |     cg.add(var.set_auto_cal(config[CONF_AUTO_CAL])) | ||||||
|  |     cg.add(var.set_bandwidth(config[CONF_BANDWIDTH])) | ||||||
|  |     cg.add(var.set_frequency(config[CONF_FREQUENCY])) | ||||||
|  |     cg.add(var.set_deviation(config[CONF_DEVIATION])) | ||||||
|  |     cg.add(var.set_modulation(config[CONF_MODULATION])) | ||||||
|  |     if config[CONF_MODULATION] != "LORA": | ||||||
|  |         cg.add(var.set_bitrate(config[CONF_BITRATE])) | ||||||
|  |         cg.add(var.set_bitsync(config[CONF_BITSYNC])) | ||||||
|  |         cg.add(var.set_packet_mode(config[CONF_PACKET_MODE])) | ||||||
|  |     cg.add(var.set_pa_pin(config[CONF_PA_PIN])) | ||||||
|  |     cg.add(var.set_pa_ramp(config[CONF_PA_RAMP])) | ||||||
|  |     cg.add(var.set_pa_power(config[CONF_PA_POWER])) | ||||||
|  |     cg.add(var.set_shaping(config[CONF_SHAPING])) | ||||||
|  |     cg.add(var.set_crc_enable(config[CONF_CRC_ENABLE])) | ||||||
|  |     cg.add(var.set_payload_length(config[CONF_PAYLOAD_LENGTH])) | ||||||
|  |     cg.add(var.set_preamble_detect(config[CONF_PREAMBLE_DETECT])) | ||||||
|  |     cg.add(var.set_preamble_size(config[CONF_PREAMBLE_SIZE])) | ||||||
|  |     cg.add(var.set_preamble_polarity(config[CONF_PREAMBLE_POLARITY])) | ||||||
|  |     cg.add(var.set_preamble_errors(config[CONF_PREAMBLE_ERRORS])) | ||||||
|  |     cg.add(var.set_coding_rate(config[CONF_CODING_RATE])) | ||||||
|  |     cg.add(var.set_spreading_factor(config[CONF_SPREADING_FACTOR])) | ||||||
|  |     cg.add(var.set_sync_value(config[CONF_SYNC_VALUE])) | ||||||
|  |     cg.add(var.set_rx_floor(config[CONF_RX_FLOOR])) | ||||||
|  |     cg.add(var.set_rx_start(config[CONF_RX_START])) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | NO_ARGS_ACTION_SCHEMA = automation.maybe_simple_id( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.use_id(SX127x), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "sx127x.run_image_cal", RunImageCalAction, NO_ARGS_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | @automation.register_action( | ||||||
|  |     "sx127x.set_mode_tx", SetModeTxAction, NO_ARGS_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | @automation.register_action( | ||||||
|  |     "sx127x.set_mode_rx", SetModeRxAction, NO_ARGS_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | @automation.register_action( | ||||||
|  |     "sx127x.set_mode_sleep", SetModeSleepAction, NO_ARGS_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | @automation.register_action( | ||||||
|  |     "sx127x.set_mode_standby", SetModeStandbyAction, NO_ARGS_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | async def no_args_action_to_code(config, action_id, template_arg, args): | ||||||
|  |     var = cg.new_Pvariable(action_id, template_arg) | ||||||
|  |     await cg.register_parented(var, config[CONF_ID]) | ||||||
|  |     return var | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SEND_PACKET_ACTION_SCHEMA = cv.maybe_simple_value( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.use_id(SX127x), | ||||||
|  |         cv.Required(CONF_DATA): cv.templatable(validate_raw_data), | ||||||
|  |     }, | ||||||
|  |     key=CONF_DATA, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "sx127x.send_packet", SendPacketAction, SEND_PACKET_ACTION_SCHEMA | ||||||
|  | ) | ||||||
|  | async def send_packet_action_to_code(config, action_id, template_arg, args): | ||||||
|  |     var = cg.new_Pvariable(action_id, template_arg) | ||||||
|  |     await cg.register_parented(var, config[CONF_ID]) | ||||||
|  |     data = config[CONF_DATA] | ||||||
|  |     if isinstance(data, bytes): | ||||||
|  |         data = list(data) | ||||||
|  |     if cg.is_template(data): | ||||||
|  |         templ = await cg.templatable(data, args, cg.std_vector.template(cg.uint8)) | ||||||
|  |         cg.add(var.set_data_template(templ)) | ||||||
|  |     else: | ||||||
|  |         cg.add(var.set_data_static(data)) | ||||||
|  |     return var | ||||||
							
								
								
									
										62
									
								
								esphome/components/sx127x/automation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								esphome/components/sx127x/automation.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/automation.h" | ||||||
|  | #include "esphome/components/sx127x/sx127x.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace sx127x { | ||||||
|  |  | ||||||
|  | template<typename... Ts> class RunImageCalAction : public Action<Ts...>, public Parented<SX127x> { | ||||||
|  |  public: | ||||||
|  |   void play(Ts... x) override { this->parent_->run_image_cal(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class SendPacketAction : public Action<Ts...>, public Parented<SX127x> { | ||||||
|  |  public: | ||||||
|  |   void set_data_template(std::function<std::vector<uint8_t>(Ts...)> func) { | ||||||
|  |     this->data_func_ = func; | ||||||
|  |     this->static_ = false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void set_data_static(const std::vector<uint8_t> &data) { | ||||||
|  |     this->data_static_ = data; | ||||||
|  |     this->static_ = true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { | ||||||
|  |     if (this->static_) { | ||||||
|  |       this->parent_->transmit_packet(this->data_static_); | ||||||
|  |     } else { | ||||||
|  |       this->parent_->transmit_packet(this->data_func_(x...)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool static_{false}; | ||||||
|  |   std::function<std::vector<uint8_t>(Ts...)> data_func_{}; | ||||||
|  |   std::vector<uint8_t> data_static_{}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class SetModeTxAction : public Action<Ts...>, public Parented<SX127x> { | ||||||
|  |  public: | ||||||
|  |   void play(Ts... x) override { this->parent_->set_mode_tx(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class SetModeRxAction : public Action<Ts...>, public Parented<SX127x> { | ||||||
|  |  public: | ||||||
|  |   void play(Ts... x) override { this->parent_->set_mode_rx(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class SetModeSleepAction : public Action<Ts...>, public Parented<SX127x> { | ||||||
|  |  public: | ||||||
|  |   void play(Ts... x) override { this->parent_->set_mode_sleep(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class SetModeStandbyAction : public Action<Ts...>, public Parented<SX127x> { | ||||||
|  |  public: | ||||||
|  |   void play(Ts... x) override { this->parent_->set_mode_standby(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace sx127x | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										26
									
								
								esphome/components/sx127x/packet_transport/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								esphome/components/sx127x/packet_transport/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | from esphome.components.packet_transport import ( | ||||||
|  |     PacketTransport, | ||||||
|  |     new_packet_transport, | ||||||
|  |     transport_schema, | ||||||
|  | ) | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.cpp_types import PollingComponent | ||||||
|  |  | ||||||
|  | from .. import CONF_SX127X_ID, SX127x, SX127xListener, sx127x_ns | ||||||
|  |  | ||||||
|  | SX127xTransport = sx127x_ns.class_( | ||||||
|  |     "SX127xTransport", PacketTransport, PollingComponent, SX127xListener | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = transport_schema(SX127xTransport).extend( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(CONF_SX127X_ID): cv.use_id(SX127x), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var, _ = await new_packet_transport(config) | ||||||
|  |     sx127x = await cg.get_variable(config[CONF_SX127X_ID]) | ||||||
|  |     cg.add(var.set_parent(sx127x)) | ||||||
| @@ -0,0 +1,26 @@ | |||||||
|  | #include "esphome/core/log.h" | ||||||
|  | #include "esphome/core/application.h" | ||||||
|  | #include "sx127x_transport.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace sx127x { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "sx127x_transport"; | ||||||
|  |  | ||||||
|  | void SX127xTransport::setup() { | ||||||
|  |   PacketTransport::setup(); | ||||||
|  |   this->parent_->register_listener(this); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127xTransport::update() { | ||||||
|  |   PacketTransport::update(); | ||||||
|  |   this->updated_ = true; | ||||||
|  |   this->resend_data_ = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127xTransport::send_packet(const std::vector<uint8_t> &buf) const { this->parent_->transmit_packet(buf); } | ||||||
|  |  | ||||||
|  | void SX127xTransport::on_packet(const std::vector<uint8_t> &packet, float rssi, float snr) { this->process_(packet); } | ||||||
|  |  | ||||||
|  | }  // namespace sx127x | ||||||
|  | }  // namespace esphome | ||||||
| @@ -0,0 +1,25 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/sx127x/sx127x.h" | ||||||
|  | #include "esphome/components/packet_transport/packet_transport.h" | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace sx127x { | ||||||
|  |  | ||||||
|  | class SX127xTransport : public packet_transport::PacketTransport, public Parented<SX127x>, public SX127xListener { | ||||||
|  |  public: | ||||||
|  |   void setup() override; | ||||||
|  |   void update() override; | ||||||
|  |   void on_packet(const std::vector<uint8_t> &packet, float rssi, float snr) override; | ||||||
|  |   float get_setup_priority() const override { return setup_priority::AFTER_WIFI; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void send_packet(const std::vector<uint8_t> &buf) const override; | ||||||
|  |   bool should_send() override { return true; } | ||||||
|  |   size_t get_max_packet_size() override { return this->parent_->get_max_packet_size(); } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace sx127x | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										493
									
								
								esphome/components/sx127x/sx127x.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										493
									
								
								esphome/components/sx127x/sx127x.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,493 @@ | |||||||
|  | #include "sx127x.h" | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace sx127x { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "sx127x"; | ||||||
|  | static const uint32_t FXOSC = 32000000u; | ||||||
|  | static const uint16_t RAMP[16] = {3400, 2000, 1000, 500, 250, 125, 100, 62, 50, 40, 31, 25, 20, 15, 12, 10}; | ||||||
|  | static const uint32_t BW_HZ[22] = {2604,  3125,  3906,  5208,  6250,  7812,   10416,  12500,  15625,  20833,  25000, | ||||||
|  |                                    31250, 41666, 50000, 62500, 83333, 100000, 125000, 166666, 200000, 250000, 500000}; | ||||||
|  | static const uint8_t BW_LORA[22] = {BW_7_8,   BW_7_8,   BW_7_8,   BW_7_8,   BW_7_8,   BW_7_8,  BW_10_4, BW_15_6, | ||||||
|  |                                     BW_15_6,  BW_20_8,  BW_31_3,  BW_31_3,  BW_41_7,  BW_62_5, BW_62_5, BW_125_0, | ||||||
|  |                                     BW_125_0, BW_125_0, BW_250_0, BW_250_0, BW_250_0, BW_500_0}; | ||||||
|  | static const uint8_t BW_FSK_OOK[22] = {RX_BW_2_6,   RX_BW_3_1,   RX_BW_3_9,   RX_BW_5_2,  RX_BW_6_3,   RX_BW_7_8, | ||||||
|  |                                        RX_BW_10_4,  RX_BW_12_5,  RX_BW_15_6,  RX_BW_20_8, RX_BW_25_0,  RX_BW_31_3, | ||||||
|  |                                        RX_BW_41_7,  RX_BW_50_0,  RX_BW_62_5,  RX_BW_83_3, RX_BW_100_0, RX_BW_125_0, | ||||||
|  |                                        RX_BW_166_7, RX_BW_200_0, RX_BW_250_0, RX_BW_250_0}; | ||||||
|  | static const int32_t RSSI_OFFSET_HF = 157; | ||||||
|  | static const int32_t RSSI_OFFSET_LF = 164; | ||||||
|  |  | ||||||
|  | uint8_t SX127x::read_register_(uint8_t reg) { | ||||||
|  |   this->enable(); | ||||||
|  |   this->write_byte(reg & 0x7F); | ||||||
|  |   uint8_t value = this->read_byte(); | ||||||
|  |   this->disable(); | ||||||
|  |   return value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::write_register_(uint8_t reg, uint8_t value) { | ||||||
|  |   this->enable(); | ||||||
|  |   this->write_byte(reg | 0x80); | ||||||
|  |   this->write_byte(value); | ||||||
|  |   this->disable(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::read_fifo_(std::vector<uint8_t> &packet) { | ||||||
|  |   this->enable(); | ||||||
|  |   this->write_byte(REG_FIFO & 0x7F); | ||||||
|  |   this->read_array(packet.data(), packet.size()); | ||||||
|  |   this->disable(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::write_fifo_(const std::vector<uint8_t> &packet) { | ||||||
|  |   this->enable(); | ||||||
|  |   this->write_byte(REG_FIFO | 0x80); | ||||||
|  |   this->write_array(packet.data(), packet.size()); | ||||||
|  |   this->disable(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Running setup"); | ||||||
|  |  | ||||||
|  |   // setup reset | ||||||
|  |   this->rst_pin_->setup(); | ||||||
|  |  | ||||||
|  |   // setup dio0 | ||||||
|  |   if (this->dio0_pin_) { | ||||||
|  |     this->dio0_pin_->setup(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // start spi | ||||||
|  |   this->spi_setup(); | ||||||
|  |  | ||||||
|  |   // configure rf | ||||||
|  |   this->configure(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::configure() { | ||||||
|  |   // toggle chip reset | ||||||
|  |   this->rst_pin_->digital_write(false); | ||||||
|  |   delayMicroseconds(1000); | ||||||
|  |   this->rst_pin_->digital_write(true); | ||||||
|  |   delayMicroseconds(10000); | ||||||
|  |  | ||||||
|  |   // check silicon version to make sure hw is ok | ||||||
|  |   if (this->read_register_(REG_VERSION) != 0x12) { | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // enter sleep mode | ||||||
|  |   this->set_mode_(MOD_FSK, MODE_SLEEP); | ||||||
|  |  | ||||||
|  |   // set freq | ||||||
|  |   uint64_t frf = ((uint64_t) this->frequency_ << 19) / FXOSC; | ||||||
|  |   this->write_register_(REG_FRF_MSB, (uint8_t) ((frf >> 16) & 0xFF)); | ||||||
|  |   this->write_register_(REG_FRF_MID, (uint8_t) ((frf >> 8) & 0xFF)); | ||||||
|  |   this->write_register_(REG_FRF_LSB, (uint8_t) ((frf >> 0) & 0xFF)); | ||||||
|  |  | ||||||
|  |   // enter standby mode | ||||||
|  |   this->set_mode_(MOD_FSK, MODE_STDBY); | ||||||
|  |  | ||||||
|  |   // run image cal | ||||||
|  |   this->run_image_cal(); | ||||||
|  |  | ||||||
|  |   // go back to sleep | ||||||
|  |   this->set_mode_sleep(); | ||||||
|  |  | ||||||
|  |   // config pa | ||||||
|  |   if (this->pa_pin_ == PA_PIN_BOOST) { | ||||||
|  |     this->pa_power_ = std::max(this->pa_power_, (uint8_t) 2); | ||||||
|  |     this->pa_power_ = std::min(this->pa_power_, (uint8_t) 17); | ||||||
|  |     this->write_register_(REG_PA_CONFIG, (this->pa_power_ - 2) | this->pa_pin_ | PA_MAX_POWER); | ||||||
|  |   } else { | ||||||
|  |     this->pa_power_ = std::min(this->pa_power_, (uint8_t) 14); | ||||||
|  |     this->write_register_(REG_PA_CONFIG, (this->pa_power_ - 0) | this->pa_pin_ | PA_MAX_POWER); | ||||||
|  |   } | ||||||
|  |   if (this->modulation_ != MOD_LORA) { | ||||||
|  |     this->write_register_(REG_PA_RAMP, this->pa_ramp_ | this->shaping_); | ||||||
|  |   } else { | ||||||
|  |     this->write_register_(REG_PA_RAMP, this->pa_ramp_); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // configure modem | ||||||
|  |   if (this->modulation_ != MOD_LORA) { | ||||||
|  |     this->configure_fsk_ook_(); | ||||||
|  |   } else { | ||||||
|  |     this->configure_lora_(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // switch to rx or sleep | ||||||
|  |   if (this->rx_start_) { | ||||||
|  |     this->set_mode_rx(); | ||||||
|  |   } else { | ||||||
|  |     this->set_mode_sleep(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::configure_fsk_ook_() { | ||||||
|  |   // set the channel bw | ||||||
|  |   this->write_register_(REG_RX_BW, BW_FSK_OOK[this->bandwidth_]); | ||||||
|  |  | ||||||
|  |   // set fdev | ||||||
|  |   uint32_t fdev = std::min((this->deviation_ * 4096) / 250000, (uint32_t) 0x3FFF); | ||||||
|  |   this->write_register_(REG_FDEV_MSB, (uint8_t) ((fdev >> 8) & 0xFF)); | ||||||
|  |   this->write_register_(REG_FDEV_LSB, (uint8_t) ((fdev >> 0) & 0xFF)); | ||||||
|  |  | ||||||
|  |   // set bitrate | ||||||
|  |   uint64_t bitrate = (FXOSC + this->bitrate_ / 2) / this->bitrate_;  // round up | ||||||
|  |   this->write_register_(REG_BITRATE_MSB, (uint8_t) ((bitrate >> 8) & 0xFF)); | ||||||
|  |   this->write_register_(REG_BITRATE_LSB, (uint8_t) ((bitrate >> 0) & 0xFF)); | ||||||
|  |  | ||||||
|  |   // configure rx and afc | ||||||
|  |   uint8_t trigger = (this->preamble_detect_ > 0) ? TRIGGER_PREAMBLE : TRIGGER_RSSI; | ||||||
|  |   this->write_register_(REG_AFC_FEI, AFC_AUTO_CLEAR_ON); | ||||||
|  |   if (this->modulation_ == MOD_FSK) { | ||||||
|  |     this->write_register_(REG_RX_CONFIG, AFC_AUTO_ON | AGC_AUTO_ON | trigger); | ||||||
|  |   } else { | ||||||
|  |     this->write_register_(REG_RX_CONFIG, AGC_AUTO_ON | trigger); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // configure packet mode | ||||||
|  |   if (this->packet_mode_) { | ||||||
|  |     uint8_t crc_mode = (this->crc_enable_) ? CRC_ON : CRC_OFF; | ||||||
|  |     this->write_register_(REG_FIFO_THRESH, TX_START_FIFO_EMPTY); | ||||||
|  |     if (this->payload_length_ > 0) { | ||||||
|  |       this->write_register_(REG_PAYLOAD_LENGTH_LSB, this->payload_length_); | ||||||
|  |       this->write_register_(REG_PACKET_CONFIG_1, crc_mode | FIXED_LENGTH); | ||||||
|  |     } else { | ||||||
|  |       this->write_register_(REG_PAYLOAD_LENGTH_LSB, this->get_max_packet_size() - 1); | ||||||
|  |       this->write_register_(REG_PACKET_CONFIG_1, crc_mode | VARIABLE_LENGTH); | ||||||
|  |     } | ||||||
|  |     this->write_register_(REG_PACKET_CONFIG_2, PACKET_MODE); | ||||||
|  |   } else { | ||||||
|  |     this->write_register_(REG_PACKET_CONFIG_2, CONTINUOUS_MODE); | ||||||
|  |   } | ||||||
|  |   this->write_register_(REG_DIO_MAPPING1, DIO0_MAPPING_00); | ||||||
|  |  | ||||||
|  |   // config bit synchronizer | ||||||
|  |   uint8_t polarity = (this->preamble_polarity_ == 0xAA) ? PREAMBLE_AA : PREAMBLE_55; | ||||||
|  |   if (!this->sync_value_.empty()) { | ||||||
|  |     uint8_t size = this->sync_value_.size() - 1; | ||||||
|  |     this->write_register_(REG_SYNC_CONFIG, AUTO_RESTART_PLL_LOCK | polarity | SYNC_ON | size); | ||||||
|  |     for (uint32_t i = 0; i < this->sync_value_.size(); i++) { | ||||||
|  |       this->write_register_(REG_SYNC_VALUE1 + i, this->sync_value_[i]); | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     this->write_register_(REG_SYNC_CONFIG, AUTO_RESTART_PLL_LOCK | polarity); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // config preamble detector | ||||||
|  |   if (this->preamble_detect_ > 0) { | ||||||
|  |     uint8_t size = (this->preamble_detect_ - 1) << PREAMBLE_DETECTOR_SIZE_SHIFT; | ||||||
|  |     uint8_t tol = this->preamble_errors_ << PREAMBLE_DETECTOR_TOL_SHIFT; | ||||||
|  |     this->write_register_(REG_PREAMBLE_DETECT, PREAMBLE_DETECTOR_ON | size | tol); | ||||||
|  |   } else { | ||||||
|  |     this->write_register_(REG_PREAMBLE_DETECT, PREAMBLE_DETECTOR_OFF); | ||||||
|  |   } | ||||||
|  |   this->write_register_(REG_PREAMBLE_SIZE_MSB, this->preamble_size_ >> 16); | ||||||
|  |   this->write_register_(REG_PREAMBLE_SIZE_LSB, this->preamble_size_ & 0xFF); | ||||||
|  |  | ||||||
|  |   // config sync generation and setup ook threshold | ||||||
|  |   uint8_t bitsync = this->bitsync_ ? BIT_SYNC_ON : BIT_SYNC_OFF; | ||||||
|  |   this->write_register_(REG_OOK_PEAK, bitsync | OOK_THRESH_STEP_0_5 | OOK_THRESH_PEAK); | ||||||
|  |   this->write_register_(REG_OOK_AVG, OOK_AVG_RESERVED | OOK_THRESH_DEC_1_8); | ||||||
|  |  | ||||||
|  |   // set rx floor | ||||||
|  |   this->write_register_(REG_OOK_FIX, 256 + int(this->rx_floor_ * 2.0)); | ||||||
|  |   this->write_register_(REG_RSSI_THRESH, std::abs(int(this->rx_floor_ * 2.0))); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::configure_lora_() { | ||||||
|  |   // config modem | ||||||
|  |   uint8_t header_mode = this->payload_length_ > 0 ? IMPLICIT_HEADER : EXPLICIT_HEADER; | ||||||
|  |   uint8_t crc_mode = (this->crc_enable_) ? RX_PAYLOAD_CRC_ON : RX_PAYLOAD_CRC_OFF; | ||||||
|  |   uint8_t spreading_factor = this->spreading_factor_ << SPREADING_FACTOR_SHIFT; | ||||||
|  |   this->write_register_(REG_MODEM_CONFIG1, BW_LORA[this->bandwidth_] | this->coding_rate_ | header_mode); | ||||||
|  |   this->write_register_(REG_MODEM_CONFIG2, spreading_factor | crc_mode); | ||||||
|  |  | ||||||
|  |   // config fifo and payload length | ||||||
|  |   this->write_register_(REG_FIFO_TX_BASE_ADDR, 0x00); | ||||||
|  |   this->write_register_(REG_FIFO_RX_BASE_ADDR, 0x00); | ||||||
|  |   this->write_register_(REG_PAYLOAD_LENGTH, std::max(this->payload_length_, (uint32_t) 1)); | ||||||
|  |  | ||||||
|  |   // config preamble | ||||||
|  |   if (this->preamble_size_ >= 6) { | ||||||
|  |     this->write_register_(REG_PREAMBLE_LEN_MSB, this->preamble_size_ >> 16); | ||||||
|  |     this->write_register_(REG_PREAMBLE_LEN_LSB, this->preamble_size_ & 0xFF); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // optimize detection | ||||||
|  |   float duration = 1000.0f * std::pow(2, this->spreading_factor_) / BW_HZ[this->bandwidth_]; | ||||||
|  |   if (duration > 16) { | ||||||
|  |     this->write_register_(REG_MODEM_CONFIG3, MODEM_AGC_AUTO_ON | LOW_DATA_RATE_OPTIMIZE_ON); | ||||||
|  |   } else { | ||||||
|  |     this->write_register_(REG_MODEM_CONFIG3, MODEM_AGC_AUTO_ON); | ||||||
|  |   } | ||||||
|  |   if (this->spreading_factor_ == 6) { | ||||||
|  |     this->write_register_(REG_DETECT_OPTIMIZE, 0xC5); | ||||||
|  |     this->write_register_(REG_DETECT_THRESHOLD, 0x0C); | ||||||
|  |   } else { | ||||||
|  |     this->write_register_(REG_DETECT_OPTIMIZE, 0xC3); | ||||||
|  |     this->write_register_(REG_DETECT_THRESHOLD, 0x0A); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // config sync word | ||||||
|  |   if (!this->sync_value_.empty()) { | ||||||
|  |     this->write_register_(REG_SYNC_WORD, this->sync_value_[0]); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | size_t SX127x::get_max_packet_size() { | ||||||
|  |   if (this->payload_length_ > 0) { | ||||||
|  |     return this->payload_length_; | ||||||
|  |   } | ||||||
|  |   if (this->modulation_ == MOD_LORA) { | ||||||
|  |     return 256; | ||||||
|  |   } else { | ||||||
|  |     return 64; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::transmit_packet(const std::vector<uint8_t> &packet) { | ||||||
|  |   if (this->payload_length_ > 0 && this->payload_length_ != packet.size()) { | ||||||
|  |     ESP_LOGE(TAG, "Packet size does not match config"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (packet.empty() || packet.size() > this->get_max_packet_size()) { | ||||||
|  |     ESP_LOGE(TAG, "Packet size out of range"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (this->modulation_ == MOD_LORA) { | ||||||
|  |     this->set_mode_standby(); | ||||||
|  |     if (this->payload_length_ == 0) { | ||||||
|  |       this->write_register_(REG_PAYLOAD_LENGTH, packet.size()); | ||||||
|  |     } | ||||||
|  |     this->write_register_(REG_IRQ_FLAGS, 0xFF); | ||||||
|  |     this->write_register_(REG_FIFO_ADDR_PTR, 0); | ||||||
|  |     this->write_fifo_(packet); | ||||||
|  |     this->set_mode_tx(); | ||||||
|  |   } else { | ||||||
|  |     this->set_mode_standby(); | ||||||
|  |     if (this->payload_length_ == 0) { | ||||||
|  |       this->write_register_(REG_FIFO, packet.size()); | ||||||
|  |     } | ||||||
|  |     this->write_fifo_(packet); | ||||||
|  |     this->set_mode_tx(); | ||||||
|  |   } | ||||||
|  |   // wait until transmit completes, typically the delay will be less than 100 ms | ||||||
|  |   uint32_t start = millis(); | ||||||
|  |   while (!this->dio0_pin_->digital_read()) { | ||||||
|  |     if (millis() - start > 4000) { | ||||||
|  |       ESP_LOGE(TAG, "Transmit packet failure"); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (this->rx_start_) { | ||||||
|  |     this->set_mode_rx(); | ||||||
|  |   } else { | ||||||
|  |     this->set_mode_sleep(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::call_listeners_(const std::vector<uint8_t> &packet, float rssi, float snr) { | ||||||
|  |   for (auto &listener : this->listeners_) { | ||||||
|  |     listener->on_packet(packet, rssi, snr); | ||||||
|  |   } | ||||||
|  |   this->packet_trigger_->trigger(packet, rssi, snr); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::loop() { | ||||||
|  |   if (this->dio0_pin_ == nullptr || !this->dio0_pin_->digital_read()) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->modulation_ == MOD_LORA) { | ||||||
|  |     uint8_t status = this->read_register_(REG_IRQ_FLAGS); | ||||||
|  |     this->write_register_(REG_IRQ_FLAGS, 0xFF); | ||||||
|  |     if ((status & PAYLOAD_CRC_ERROR) == 0) { | ||||||
|  |       uint8_t bytes = this->read_register_(REG_NB_RX_BYTES); | ||||||
|  |       uint8_t addr = this->read_register_(REG_FIFO_RX_CURR_ADDR); | ||||||
|  |       uint8_t rssi = this->read_register_(REG_PKT_RSSI_VALUE); | ||||||
|  |       int8_t snr = (int8_t) this->read_register_(REG_PKT_SNR_VALUE); | ||||||
|  |       std::vector<uint8_t> packet(bytes); | ||||||
|  |       this->write_register_(REG_FIFO_ADDR_PTR, addr); | ||||||
|  |       this->read_fifo_(packet); | ||||||
|  |       if (this->frequency_ > 700000000) { | ||||||
|  |         this->call_listeners_(packet, (float) rssi - RSSI_OFFSET_HF, (float) snr / 4); | ||||||
|  |       } else { | ||||||
|  |         this->call_listeners_(packet, (float) rssi - RSSI_OFFSET_LF, (float) snr / 4); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } else if (this->packet_mode_) { | ||||||
|  |     std::vector<uint8_t> packet; | ||||||
|  |     uint8_t payload_length = this->payload_length_; | ||||||
|  |     if (payload_length == 0) { | ||||||
|  |       payload_length = this->read_register_(REG_FIFO); | ||||||
|  |     } | ||||||
|  |     packet.resize(payload_length); | ||||||
|  |     this->read_fifo_(packet); | ||||||
|  |     this->call_listeners_(packet, 0.0f, 0.0f); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::run_image_cal() { | ||||||
|  |   uint32_t start = millis(); | ||||||
|  |   uint8_t mode = this->read_register_(REG_OP_MODE); | ||||||
|  |   if ((mode & MODE_MASK) != MODE_STDBY) { | ||||||
|  |     ESP_LOGE(TAG, "Need to be in standby for image cal"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (mode & MOD_LORA) { | ||||||
|  |     this->set_mode_(MOD_FSK, MODE_SLEEP); | ||||||
|  |     this->set_mode_(MOD_FSK, MODE_STDBY); | ||||||
|  |   } | ||||||
|  |   if (this->auto_cal_) { | ||||||
|  |     this->write_register_(REG_IMAGE_CAL, IMAGE_CAL_START | AUTO_IMAGE_CAL_ON | TEMP_THRESHOLD_10C); | ||||||
|  |   } else { | ||||||
|  |     this->write_register_(REG_IMAGE_CAL, IMAGE_CAL_START); | ||||||
|  |   } | ||||||
|  |   while (this->read_register_(REG_IMAGE_CAL) & IMAGE_CAL_RUNNING) { | ||||||
|  |     if (millis() - start > 20) { | ||||||
|  |       ESP_LOGE(TAG, "Image cal failure"); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (mode & MOD_LORA) { | ||||||
|  |     this->set_mode_(this->modulation_, MODE_SLEEP); | ||||||
|  |     this->set_mode_(this->modulation_, MODE_STDBY); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::set_mode_(uint8_t modulation, uint8_t mode) { | ||||||
|  |   uint32_t start = millis(); | ||||||
|  |   this->write_register_(REG_OP_MODE, modulation | mode); | ||||||
|  |   while (true) { | ||||||
|  |     uint8_t curr = this->read_register_(REG_OP_MODE) & MODE_MASK; | ||||||
|  |     if ((curr == mode) || (mode == MODE_RX && curr == MODE_RX_FS)) { | ||||||
|  |       if (mode == MODE_SLEEP) { | ||||||
|  |         this->write_register_(REG_OP_MODE, modulation | mode); | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |     if (millis() - start > 20) { | ||||||
|  |       ESP_LOGE(TAG, "Set mode failure"); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::set_mode_rx() { | ||||||
|  |   this->set_mode_(this->modulation_, MODE_RX); | ||||||
|  |   if (this->modulation_ == MOD_LORA) { | ||||||
|  |     this->write_register_(REG_IRQ_FLAGS_MASK, 0x00); | ||||||
|  |     this->write_register_(REG_DIO_MAPPING1, DIO0_MAPPING_00); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::set_mode_tx() { | ||||||
|  |   this->set_mode_(this->modulation_, MODE_TX); | ||||||
|  |   if (this->modulation_ == MOD_LORA) { | ||||||
|  |     this->write_register_(REG_IRQ_FLAGS_MASK, 0x00); | ||||||
|  |     this->write_register_(REG_DIO_MAPPING1, DIO0_MAPPING_01); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SX127x::set_mode_standby() { this->set_mode_(this->modulation_, MODE_STDBY); } | ||||||
|  |  | ||||||
|  | void SX127x::set_mode_sleep() { this->set_mode_(this->modulation_, MODE_SLEEP); } | ||||||
|  |  | ||||||
|  | void SX127x::dump_config() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "SX127x:"); | ||||||
|  |   LOG_PIN("  CS Pin: ", this->cs_); | ||||||
|  |   LOG_PIN("  RST Pin: ", this->rst_pin_); | ||||||
|  |   LOG_PIN("  DIO0 Pin: ", this->dio0_pin_); | ||||||
|  |   const char *shaping = "NONE"; | ||||||
|  |   if (this->shaping_ == CUTOFF_BR_X_2) { | ||||||
|  |     shaping = "CUTOFF_BR_X_2"; | ||||||
|  |   } else if (this->shaping_ == CUTOFF_BR_X_1) { | ||||||
|  |     shaping = "CUTOFF_BR_X_1"; | ||||||
|  |   } else if (this->shaping_ == GAUSSIAN_BT_0_3) { | ||||||
|  |     shaping = "GAUSSIAN_BT_0_3"; | ||||||
|  |   } else if (this->shaping_ == GAUSSIAN_BT_0_5) { | ||||||
|  |     shaping = "GAUSSIAN_BT_0_5"; | ||||||
|  |   } else if (this->shaping_ == GAUSSIAN_BT_1_0) { | ||||||
|  |     shaping = "GAUSSIAN_BT_1_0"; | ||||||
|  |   } | ||||||
|  |   const char *pa_pin = "RFO"; | ||||||
|  |   if (this->pa_pin_ == PA_PIN_BOOST) { | ||||||
|  |     pa_pin = "BOOST"; | ||||||
|  |   } | ||||||
|  |   ESP_LOGCONFIG(TAG, | ||||||
|  |                 "  Auto Cal: %s\n" | ||||||
|  |                 "  Frequency: %" PRIu32 " Hz\n" | ||||||
|  |                 "  Bandwidth: %" PRIu32 " Hz\n" | ||||||
|  |                 "  PA Pin: %s\n" | ||||||
|  |                 "  PA Power: %" PRIu8 " dBm\n" | ||||||
|  |                 "  PA Ramp: %" PRIu16 " us\n" | ||||||
|  |                 "  Shaping: %s", | ||||||
|  |                 TRUEFALSE(this->auto_cal_), this->frequency_, BW_HZ[this->bandwidth_], pa_pin, this->pa_power_, | ||||||
|  |                 RAMP[this->pa_ramp_], shaping); | ||||||
|  |   if (this->modulation_ == MOD_FSK) { | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Deviation: %" PRIu32 " Hz", this->deviation_); | ||||||
|  |   } | ||||||
|  |   if (this->modulation_ == MOD_LORA) { | ||||||
|  |     const char *cr = "4/8"; | ||||||
|  |     if (this->coding_rate_ == CODING_RATE_4_5) { | ||||||
|  |       cr = "4/5"; | ||||||
|  |     } else if (this->coding_rate_ == CODING_RATE_4_6) { | ||||||
|  |       cr = "4/6"; | ||||||
|  |     } else if (this->coding_rate_ == CODING_RATE_4_7) { | ||||||
|  |       cr = "4/7"; | ||||||
|  |     } | ||||||
|  |     ESP_LOGCONFIG(TAG, | ||||||
|  |                   "  Modulation: LORA\n" | ||||||
|  |                   "  Preamble Size: %" PRIu16 "\n" | ||||||
|  |                   "  Spreading Factor: %" PRIu8 "\n" | ||||||
|  |                   "  Coding Rate: %s\n" | ||||||
|  |                   "  CRC Enable: %s", | ||||||
|  |                   this->preamble_size_, this->spreading_factor_, cr, TRUEFALSE(this->crc_enable_)); | ||||||
|  |     if (this->payload_length_ > 0) { | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Payload Length: %" PRIu32, this->payload_length_); | ||||||
|  |     } | ||||||
|  |     if (!this->sync_value_.empty()) { | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Sync Value: 0x%02x", this->sync_value_[0]); | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     ESP_LOGCONFIG(TAG, | ||||||
|  |                   "  Modulation: %s\n" | ||||||
|  |                   "  Bitrate: %" PRIu32 "b/s\n" | ||||||
|  |                   "  Bitsync: %s\n" | ||||||
|  |                   "  Rx Start: %s\n" | ||||||
|  |                   "  Rx Floor: %.1f dBm\n" | ||||||
|  |                   "  Packet Mode: %s", | ||||||
|  |                   this->modulation_ == MOD_FSK ? "FSK" : "OOK", this->bitrate_, TRUEFALSE(this->bitsync_), | ||||||
|  |                   TRUEFALSE(this->rx_start_), this->rx_floor_, TRUEFALSE(this->packet_mode_)); | ||||||
|  |     if (this->packet_mode_) { | ||||||
|  |       ESP_LOGCONFIG(TAG, "  CRC Enable: %s", TRUEFALSE(this->crc_enable_)); | ||||||
|  |     } | ||||||
|  |     if (this->payload_length_ > 0) { | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Payload Length: %" PRIu32, this->payload_length_); | ||||||
|  |     } | ||||||
|  |     if (!this->sync_value_.empty()) { | ||||||
|  |       ESP_LOGCONFIG(TAG, "  Sync Value: 0x%s", format_hex(this->sync_value_).c_str()); | ||||||
|  |     } | ||||||
|  |     if (this->preamble_size_ > 0 || this->preamble_detect_ > 0) { | ||||||
|  |       ESP_LOGCONFIG(TAG, | ||||||
|  |                     "  Preamble Polarity: 0x%X\n" | ||||||
|  |                     "  Preamble Size: %" PRIu16 "\n" | ||||||
|  |                     "  Preamble Detect: %" PRIu8 "\n" | ||||||
|  |                     "  Preamble Errors: %" PRIu8, | ||||||
|  |                     this->preamble_polarity_, this->preamble_size_, this->preamble_detect_, this->preamble_errors_); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (this->is_failed()) { | ||||||
|  |     ESP_LOGE(TAG, "Configuring SX127x failed"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace sx127x | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										125
									
								
								esphome/components/sx127x/sx127x.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								esphome/components/sx127x/sx127x.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "sx127x_reg.h" | ||||||
|  | #include "esphome/components/spi/spi.h" | ||||||
|  | #include "esphome/core/automation.h" | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace sx127x { | ||||||
|  |  | ||||||
|  | enum SX127xBw : uint8_t { | ||||||
|  |   SX127X_BW_2_6, | ||||||
|  |   SX127X_BW_3_1, | ||||||
|  |   SX127X_BW_3_9, | ||||||
|  |   SX127X_BW_5_2, | ||||||
|  |   SX127X_BW_6_3, | ||||||
|  |   SX127X_BW_7_8, | ||||||
|  |   SX127X_BW_10_4, | ||||||
|  |   SX127X_BW_12_5, | ||||||
|  |   SX127X_BW_15_6, | ||||||
|  |   SX127X_BW_20_8, | ||||||
|  |   SX127X_BW_25_0, | ||||||
|  |   SX127X_BW_31_3, | ||||||
|  |   SX127X_BW_41_7, | ||||||
|  |   SX127X_BW_50_0, | ||||||
|  |   SX127X_BW_62_5, | ||||||
|  |   SX127X_BW_83_3, | ||||||
|  |   SX127X_BW_100_0, | ||||||
|  |   SX127X_BW_125_0, | ||||||
|  |   SX127X_BW_166_7, | ||||||
|  |   SX127X_BW_200_0, | ||||||
|  |   SX127X_BW_250_0, | ||||||
|  |   SX127X_BW_500_0, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class SX127xListener { | ||||||
|  |  public: | ||||||
|  |   virtual void on_packet(const std::vector<uint8_t> &packet, float rssi, float snr) = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class SX127x : public Component, | ||||||
|  |                public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING, | ||||||
|  |                                      spi::DATA_RATE_8MHZ> { | ||||||
|  |  public: | ||||||
|  |   size_t get_max_packet_size(); | ||||||
|  |   float get_setup_priority() const override { return setup_priority::PROCESSOR; } | ||||||
|  |   void setup() override; | ||||||
|  |   void loop() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |   void set_auto_cal(bool auto_cal) { this->auto_cal_ = auto_cal; } | ||||||
|  |   void set_bandwidth(SX127xBw bandwidth) { this->bandwidth_ = bandwidth; } | ||||||
|  |   void set_bitrate(uint32_t bitrate) { this->bitrate_ = bitrate; } | ||||||
|  |   void set_bitsync(bool bitsync) { this->bitsync_ = bitsync; } | ||||||
|  |   void set_coding_rate(uint8_t coding_rate) { this->coding_rate_ = coding_rate; } | ||||||
|  |   void set_crc_enable(bool crc_enable) { this->crc_enable_ = crc_enable; } | ||||||
|  |   void set_deviation(uint32_t deviation) { this->deviation_ = deviation; } | ||||||
|  |   void set_dio0_pin(InternalGPIOPin *dio0_pin) { this->dio0_pin_ = dio0_pin; } | ||||||
|  |   void set_frequency(uint32_t frequency) { this->frequency_ = frequency; } | ||||||
|  |   void set_mode_rx(); | ||||||
|  |   void set_mode_tx(); | ||||||
|  |   void set_mode_standby(); | ||||||
|  |   void set_mode_sleep(); | ||||||
|  |   void set_modulation(uint8_t modulation) { this->modulation_ = modulation; } | ||||||
|  |   void set_pa_pin(uint8_t pin) { this->pa_pin_ = pin; } | ||||||
|  |   void set_pa_power(uint8_t power) { this->pa_power_ = power; } | ||||||
|  |   void set_pa_ramp(uint8_t ramp) { this->pa_ramp_ = ramp; } | ||||||
|  |   void set_packet_mode(bool packet_mode) { this->packet_mode_ = packet_mode; } | ||||||
|  |   void set_payload_length(uint8_t payload_length) { this->payload_length_ = payload_length; } | ||||||
|  |   void set_preamble_errors(uint8_t preamble_errors) { this->preamble_errors_ = preamble_errors; } | ||||||
|  |   void set_preamble_polarity(uint8_t preamble_polarity) { this->preamble_polarity_ = preamble_polarity; } | ||||||
|  |   void set_preamble_size(uint16_t preamble_size) { this->preamble_size_ = preamble_size; } | ||||||
|  |   void set_preamble_detect(uint8_t preamble_detect) { this->preamble_detect_ = preamble_detect; } | ||||||
|  |   void set_rst_pin(InternalGPIOPin *rst_pin) { this->rst_pin_ = rst_pin; } | ||||||
|  |   void set_rx_floor(float floor) { this->rx_floor_ = floor; } | ||||||
|  |   void set_rx_start(bool start) { this->rx_start_ = start; } | ||||||
|  |   void set_shaping(uint8_t shaping) { this->shaping_ = shaping; } | ||||||
|  |   void set_spreading_factor(uint8_t spreading_factor) { this->spreading_factor_ = spreading_factor; } | ||||||
|  |   void set_sync_value(const std::vector<uint8_t> &sync_value) { this->sync_value_ = sync_value; } | ||||||
|  |   void run_image_cal(); | ||||||
|  |   void configure(); | ||||||
|  |   void transmit_packet(const std::vector<uint8_t> &packet); | ||||||
|  |   void register_listener(SX127xListener *listener) { this->listeners_.push_back(listener); } | ||||||
|  |   Trigger<std::vector<uint8_t>, float, float> *get_packet_trigger() const { return this->packet_trigger_; }; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void configure_fsk_ook_(); | ||||||
|  |   void configure_lora_(); | ||||||
|  |   void set_mode_(uint8_t modulation, uint8_t mode); | ||||||
|  |   void write_fifo_(const std::vector<uint8_t> &packet); | ||||||
|  |   void read_fifo_(std::vector<uint8_t> &packet); | ||||||
|  |   void write_register_(uint8_t reg, uint8_t value); | ||||||
|  |   void call_listeners_(const std::vector<uint8_t> &packet, float rssi, float snr); | ||||||
|  |   uint8_t read_register_(uint8_t reg); | ||||||
|  |   Trigger<std::vector<uint8_t>, float, float> *packet_trigger_{new Trigger<std::vector<uint8_t>, float, float>()}; | ||||||
|  |   std::vector<SX127xListener *> listeners_; | ||||||
|  |   std::vector<uint8_t> sync_value_; | ||||||
|  |   InternalGPIOPin *dio0_pin_{nullptr}; | ||||||
|  |   InternalGPIOPin *rst_pin_{nullptr}; | ||||||
|  |   SX127xBw bandwidth_; | ||||||
|  |   uint32_t bitrate_; | ||||||
|  |   uint32_t deviation_; | ||||||
|  |   uint32_t frequency_; | ||||||
|  |   uint32_t payload_length_; | ||||||
|  |   uint16_t preamble_size_; | ||||||
|  |   uint8_t coding_rate_; | ||||||
|  |   uint8_t modulation_; | ||||||
|  |   uint8_t pa_pin_; | ||||||
|  |   uint8_t pa_power_; | ||||||
|  |   uint8_t pa_ramp_; | ||||||
|  |   uint8_t preamble_detect_; | ||||||
|  |   uint8_t preamble_errors_; | ||||||
|  |   uint8_t preamble_polarity_; | ||||||
|  |   uint8_t shaping_; | ||||||
|  |   uint8_t spreading_factor_; | ||||||
|  |   float rx_floor_; | ||||||
|  |   bool auto_cal_{false}; | ||||||
|  |   bool bitsync_{false}; | ||||||
|  |   bool crc_enable_{false}; | ||||||
|  |   bool packet_mode_{false}; | ||||||
|  |   bool rx_start_{false}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace sx127x | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										295
									
								
								esphome/components/sx127x/sx127x_reg.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								esphome/components/sx127x/sx127x_reg.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,295 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace sx127x { | ||||||
|  |  | ||||||
|  | enum SX127xReg : uint8_t { | ||||||
|  |   // Common registers | ||||||
|  |   REG_FIFO = 0x00, | ||||||
|  |   REG_OP_MODE = 0x01, | ||||||
|  |   REG_BITRATE_MSB = 0x02, | ||||||
|  |   REG_BITRATE_LSB = 0x03, | ||||||
|  |   REG_FDEV_MSB = 0x04, | ||||||
|  |   REG_FDEV_LSB = 0x05, | ||||||
|  |   REG_FRF_MSB = 0x06, | ||||||
|  |   REG_FRF_MID = 0x07, | ||||||
|  |   REG_FRF_LSB = 0x08, | ||||||
|  |   REG_PA_CONFIG = 0x09, | ||||||
|  |   REG_PA_RAMP = 0x0A, | ||||||
|  |   REG_DIO_MAPPING1 = 0x40, | ||||||
|  |   REG_DIO_MAPPING2 = 0x41, | ||||||
|  |   REG_VERSION = 0x42, | ||||||
|  |   // FSK/OOK registers | ||||||
|  |   REG_RX_CONFIG = 0x0D, | ||||||
|  |   REG_RSSI_THRESH = 0x10, | ||||||
|  |   REG_RX_BW = 0x12, | ||||||
|  |   REG_OOK_PEAK = 0x14, | ||||||
|  |   REG_OOK_FIX = 0x15, | ||||||
|  |   REG_OOK_AVG = 0x16, | ||||||
|  |   REG_AFC_FEI = 0x1A, | ||||||
|  |   REG_PREAMBLE_DETECT = 0x1F, | ||||||
|  |   REG_PREAMBLE_SIZE_MSB = 0x25, | ||||||
|  |   REG_PREAMBLE_SIZE_LSB = 0x26, | ||||||
|  |   REG_SYNC_CONFIG = 0x27, | ||||||
|  |   REG_SYNC_VALUE1 = 0x28, | ||||||
|  |   REG_SYNC_VALUE2 = 0x29, | ||||||
|  |   REG_SYNC_VALUE3 = 0x2A, | ||||||
|  |   REG_SYNC_VALUE4 = 0x2B, | ||||||
|  |   REG_SYNC_VALUE5 = 0x2C, | ||||||
|  |   REG_SYNC_VALUE6 = 0x2D, | ||||||
|  |   REG_SYNC_VALUE7 = 0x2E, | ||||||
|  |   REG_SYNC_VALUE8 = 0x2F, | ||||||
|  |   REG_PACKET_CONFIG_1 = 0x30, | ||||||
|  |   REG_PACKET_CONFIG_2 = 0x31, | ||||||
|  |   REG_PAYLOAD_LENGTH_LSB = 0x32, | ||||||
|  |   REG_FIFO_THRESH = 0x35, | ||||||
|  |   REG_IMAGE_CAL = 0x3B, | ||||||
|  |   // LoRa registers | ||||||
|  |   REG_FIFO_ADDR_PTR = 0x0D, | ||||||
|  |   REG_FIFO_TX_BASE_ADDR = 0x0E, | ||||||
|  |   REG_FIFO_RX_BASE_ADDR = 0x0F, | ||||||
|  |   REG_FIFO_RX_CURR_ADDR = 0x10, | ||||||
|  |   REG_IRQ_FLAGS_MASK = 0x11, | ||||||
|  |   REG_IRQ_FLAGS = 0x12, | ||||||
|  |   REG_NB_RX_BYTES = 0x13, | ||||||
|  |   REG_MODEM_STAT = 0x18, | ||||||
|  |   REG_PKT_SNR_VALUE = 0x19, | ||||||
|  |   REG_PKT_RSSI_VALUE = 0x1A, | ||||||
|  |   REG_RSSI_VALUE = 0x1B, | ||||||
|  |   REG_HOP_CHANNEL = 0x1C, | ||||||
|  |   REG_MODEM_CONFIG1 = 0x1D, | ||||||
|  |   REG_MODEM_CONFIG2 = 0x1E, | ||||||
|  |   REG_SYMB_TIMEOUT_LSB = 0x1F, | ||||||
|  |   REG_PREAMBLE_LEN_MSB = 0x20, | ||||||
|  |   REG_PREAMBLE_LEN_LSB = 0x21, | ||||||
|  |   REG_PAYLOAD_LENGTH = 0x22, | ||||||
|  |   REG_HOP_PERIOD = 0x24, | ||||||
|  |   REG_FIFO_RX_BYTE_ADDR = 0x25, | ||||||
|  |   REG_MODEM_CONFIG3 = 0x26, | ||||||
|  |   REG_FEI_MSB = 0x28, | ||||||
|  |   REG_FEI_MIB = 0x29, | ||||||
|  |   REG_FEI_LSB = 0x2A, | ||||||
|  |   REG_DETECT_OPTIMIZE = 0x31, | ||||||
|  |   REG_INVERT_IQ = 0x33, | ||||||
|  |   REG_DETECT_THRESHOLD = 0x37, | ||||||
|  |   REG_SYNC_WORD = 0x39, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xOpMode : uint8_t { | ||||||
|  |   MOD_LORA = 0x80, | ||||||
|  |   ACCESS_FSK_REGS = 0x40, | ||||||
|  |   ACCESS_LORA_REGS = 0x00, | ||||||
|  |   MOD_OOK = 0x20, | ||||||
|  |   MOD_FSK = 0x00, | ||||||
|  |   ACCESS_LF_REGS = 0x08, | ||||||
|  |   ACCESS_HF_REGS = 0x00, | ||||||
|  |   MODE_CAD = 0x07, | ||||||
|  |   MODE_RX_SINGLE = 0x06, | ||||||
|  |   MODE_RX = 0x05, | ||||||
|  |   MODE_RX_FS = 0x04, | ||||||
|  |   MODE_TX = 0x03, | ||||||
|  |   MODE_TX_FS = 0x02, | ||||||
|  |   MODE_STDBY = 0x01, | ||||||
|  |   MODE_SLEEP = 0x00, | ||||||
|  |   MODE_MASK = 0x07, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xPaConfig : uint8_t { | ||||||
|  |   PA_PIN_BOOST = 0x80, | ||||||
|  |   PA_PIN_RFO = 0x00, | ||||||
|  |   PA_MAX_POWER = 0x70, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xPaRamp : uint8_t { | ||||||
|  |   CUTOFF_BR_X_2 = 0x40, | ||||||
|  |   CUTOFF_BR_X_1 = 0x20, | ||||||
|  |   GAUSSIAN_BT_0_3 = 0x60, | ||||||
|  |   GAUSSIAN_BT_0_5 = 0x40, | ||||||
|  |   GAUSSIAN_BT_1_0 = 0x20, | ||||||
|  |   SHAPING_NONE = 0x00, | ||||||
|  |   PA_RAMP_10 = 0x0F, | ||||||
|  |   PA_RAMP_12 = 0x0E, | ||||||
|  |   PA_RAMP_15 = 0x0D, | ||||||
|  |   PA_RAMP_20 = 0x0C, | ||||||
|  |   PA_RAMP_25 = 0x0B, | ||||||
|  |   PA_RAMP_31 = 0x0A, | ||||||
|  |   PA_RAMP_40 = 0x09, | ||||||
|  |   PA_RAMP_50 = 0x08, | ||||||
|  |   PA_RAMP_62 = 0x07, | ||||||
|  |   PA_RAMP_100 = 0x06, | ||||||
|  |   PA_RAMP_125 = 0x05, | ||||||
|  |   PA_RAMP_250 = 0x04, | ||||||
|  |   PA_RAMP_500 = 0x03, | ||||||
|  |   PA_RAMP_1000 = 0x02, | ||||||
|  |   PA_RAMP_2000 = 0x01, | ||||||
|  |   PA_RAMP_3400 = 0x00, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xDioMapping1 : uint8_t { | ||||||
|  |   DIO0_MAPPING_00 = 0x00, | ||||||
|  |   DIO0_MAPPING_01 = 0x40, | ||||||
|  |   DIO0_MAPPING_10 = 0x80, | ||||||
|  |   DIO0_MAPPING_11 = 0xC0, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xRxConfig : uint8_t { | ||||||
|  |   RESTART_ON_COLLISION = 0x80, | ||||||
|  |   RESTART_NO_LOCK = 0x40, | ||||||
|  |   RESTART_PLL_LOCK = 0x20, | ||||||
|  |   AFC_AUTO_ON = 0x10, | ||||||
|  |   AGC_AUTO_ON = 0x08, | ||||||
|  |   TRIGGER_NONE = 0x00, | ||||||
|  |   TRIGGER_RSSI = 0x01, | ||||||
|  |   TRIGGER_PREAMBLE = 0x06, | ||||||
|  |   TRIGGER_ALL = 0x07, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xRxBw : uint8_t { | ||||||
|  |   RX_BW_2_6 = 0x17, | ||||||
|  |   RX_BW_3_1 = 0x0F, | ||||||
|  |   RX_BW_3_9 = 0x07, | ||||||
|  |   RX_BW_5_2 = 0x16, | ||||||
|  |   RX_BW_6_3 = 0x0E, | ||||||
|  |   RX_BW_7_8 = 0x06, | ||||||
|  |   RX_BW_10_4 = 0x15, | ||||||
|  |   RX_BW_12_5 = 0x0D, | ||||||
|  |   RX_BW_15_6 = 0x05, | ||||||
|  |   RX_BW_20_8 = 0x14, | ||||||
|  |   RX_BW_25_0 = 0x0C, | ||||||
|  |   RX_BW_31_3 = 0x04, | ||||||
|  |   RX_BW_41_7 = 0x13, | ||||||
|  |   RX_BW_50_0 = 0x0B, | ||||||
|  |   RX_BW_62_5 = 0x03, | ||||||
|  |   RX_BW_83_3 = 0x12, | ||||||
|  |   RX_BW_100_0 = 0x0A, | ||||||
|  |   RX_BW_125_0 = 0x02, | ||||||
|  |   RX_BW_166_7 = 0x11, | ||||||
|  |   RX_BW_200_0 = 0x09, | ||||||
|  |   RX_BW_250_0 = 0x01, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xOokPeak : uint8_t { | ||||||
|  |   BIT_SYNC_ON = 0x20, | ||||||
|  |   BIT_SYNC_OFF = 0x00, | ||||||
|  |   OOK_THRESH_AVG = 0x10, | ||||||
|  |   OOK_THRESH_PEAK = 0x08, | ||||||
|  |   OOK_THRESH_FIXED = 0x00, | ||||||
|  |   OOK_THRESH_STEP_6_0 = 0x07, | ||||||
|  |   OOK_THRESH_STEP_5_0 = 0x06, | ||||||
|  |   OOK_THRESH_STEP_4_0 = 0x05, | ||||||
|  |   OOK_THRESH_STEP_3_0 = 0x04, | ||||||
|  |   OOK_THRESH_STEP_2_0 = 0x03, | ||||||
|  |   OOK_THRESH_STEP_1_5 = 0x02, | ||||||
|  |   OOK_THRESH_STEP_1_0 = 0x01, | ||||||
|  |   OOK_THRESH_STEP_0_5 = 0x00, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xOokAvg : uint8_t { | ||||||
|  |   OOK_THRESH_DEC_16 = 0xE0, | ||||||
|  |   OOK_THRESH_DEC_8 = 0xC0, | ||||||
|  |   OOK_THRESH_DEC_4 = 0xA0, | ||||||
|  |   OOK_THRESH_DEC_2 = 0x80, | ||||||
|  |   OOK_THRESH_DEC_1_8 = 0x60, | ||||||
|  |   OOK_THRESH_DEC_1_4 = 0x40, | ||||||
|  |   OOK_THRESH_DEC_1_2 = 0x20, | ||||||
|  |   OOK_THRESH_DEC_1 = 0x00, | ||||||
|  |   OOK_AVG_RESERVED = 0x10, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xAfcFei : uint8_t { | ||||||
|  |   AFC_AUTO_CLEAR_ON = 0x01, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xPreambleDetect : uint8_t { | ||||||
|  |   PREAMBLE_DETECTOR_ON = 0x80, | ||||||
|  |   PREAMBLE_DETECTOR_OFF = 0x00, | ||||||
|  |   PREAMBLE_DETECTOR_SIZE_SHIFT = 5, | ||||||
|  |   PREAMBLE_DETECTOR_TOL_SHIFT = 0, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xSyncConfig : uint8_t { | ||||||
|  |   AUTO_RESTART_PLL_LOCK = 0x80, | ||||||
|  |   AUTO_RESTART_NO_LOCK = 0x40, | ||||||
|  |   AUTO_RESTART_OFF = 0x00, | ||||||
|  |   PREAMBLE_55 = 0x20, | ||||||
|  |   PREAMBLE_AA = 0x00, | ||||||
|  |   SYNC_ON = 0x10, | ||||||
|  |   SYNC_OFF = 0x00, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xPacketConfig1 : uint8_t { | ||||||
|  |   VARIABLE_LENGTH = 0x80, | ||||||
|  |   FIXED_LENGTH = 0x00, | ||||||
|  |   CRC_ON = 0x10, | ||||||
|  |   CRC_OFF = 0x00, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xPacketConfig2 : uint8_t { | ||||||
|  |   CONTINUOUS_MODE = 0x00, | ||||||
|  |   PACKET_MODE = 0x40, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xFifoThresh : uint8_t { | ||||||
|  |   TX_START_FIFO_EMPTY = 0x80, | ||||||
|  |   TX_START_FIFO_LEVEL = 0x00, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xImageCal : uint8_t { | ||||||
|  |   AUTO_IMAGE_CAL_ON = 0x80, | ||||||
|  |   IMAGE_CAL_START = 0x40, | ||||||
|  |   IMAGE_CAL_RUNNING = 0x20, | ||||||
|  |   TEMP_CHANGE = 0x08, | ||||||
|  |   TEMP_THRESHOLD_20C = 0x06, | ||||||
|  |   TEMP_THRESHOLD_15C = 0x04, | ||||||
|  |   TEMP_THRESHOLD_10C = 0x02, | ||||||
|  |   TEMP_THRESHOLD_5C = 0x00, | ||||||
|  |   TEMP_MONITOR_OFF = 0x01, | ||||||
|  |   TEMP_MONITOR_ON = 0x00, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xIrqFlags : uint8_t { | ||||||
|  |   RX_TIMEOUT = 0x80, | ||||||
|  |   RX_DONE = 0x40, | ||||||
|  |   PAYLOAD_CRC_ERROR = 0x20, | ||||||
|  |   VALID_HEADER = 0x10, | ||||||
|  |   TX_DONE = 0x08, | ||||||
|  |   CAD_DONE = 0x04, | ||||||
|  |   FHSS_CHANGE_CHANNEL = 0x02, | ||||||
|  |   CAD_DETECTED = 0x01, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xModemCfg1 : uint8_t { | ||||||
|  |   BW_7_8 = 0x00, | ||||||
|  |   BW_10_4 = 0x10, | ||||||
|  |   BW_15_6 = 0x20, | ||||||
|  |   BW_20_8 = 0x30, | ||||||
|  |   BW_31_3 = 0x40, | ||||||
|  |   BW_41_7 = 0x50, | ||||||
|  |   BW_62_5 = 0x60, | ||||||
|  |   BW_125_0 = 0x70, | ||||||
|  |   BW_250_0 = 0x80, | ||||||
|  |   BW_500_0 = 0x90, | ||||||
|  |   CODING_RATE_4_5 = 0x02, | ||||||
|  |   CODING_RATE_4_6 = 0x04, | ||||||
|  |   CODING_RATE_4_7 = 0x06, | ||||||
|  |   CODING_RATE_4_8 = 0x08, | ||||||
|  |   IMPLICIT_HEADER = 0x01, | ||||||
|  |   EXPLICIT_HEADER = 0x00, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xModemCfg2 : uint8_t { | ||||||
|  |   SPREADING_FACTOR_SHIFT = 4, | ||||||
|  |   TX_CONTINOUS_MODE = 0x08, | ||||||
|  |   RX_PAYLOAD_CRC_ON = 0x04, | ||||||
|  |   RX_PAYLOAD_CRC_OFF = 0x00, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum SX127xModemCfg3 : uint8_t { | ||||||
|  |   LOW_DATA_RATE_OPTIMIZE_ON = 0x08, | ||||||
|  |   MODEM_AGC_AUTO_ON = 0x04, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace sx127x | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										45
									
								
								tests/components/sx127x/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								tests/components/sx127x/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | spi: | ||||||
|  |   clk_pin: ${clk_pin} | ||||||
|  |   mosi_pin: ${mosi_pin} | ||||||
|  |   miso_pin: ${miso_pin} | ||||||
|  |  | ||||||
|  | sx127x: | ||||||
|  |   cs_pin: ${cs_pin} | ||||||
|  |   rst_pin: ${rst_pin} | ||||||
|  |   dio0_pin: ${dio0_pin} | ||||||
|  |   pa_pin: BOOST | ||||||
|  |   pa_power: 17 | ||||||
|  |   pa_ramp: 40us | ||||||
|  |   bitsync: true | ||||||
|  |   bitrate: 4800 | ||||||
|  |   bandwidth: 50_0kHz | ||||||
|  |   frequency: 433920000 | ||||||
|  |   modulation: FSK | ||||||
|  |   deviation: 5000 | ||||||
|  |   rx_start: true | ||||||
|  |   rx_floor: -90 | ||||||
|  |   packet_mode: true | ||||||
|  |   payload_length: 8 | ||||||
|  |   sync_value: [0x33, 0x33] | ||||||
|  |   shaping: NONE | ||||||
|  |   preamble_size: 2 | ||||||
|  |   preamble_detect: 2 | ||||||
|  |   preamble_errors: 8 | ||||||
|  |   preamble_polarity: 0x55 | ||||||
|  |   on_packet: | ||||||
|  |     then: | ||||||
|  |       - sx127x.send_packet: | ||||||
|  |           data: [0xC5, 0x51, 0x78, 0x82, 0xB7, 0xF9, 0x9C, 0x5C] | ||||||
|  |  | ||||||
|  | button: | ||||||
|  |   - platform: template | ||||||
|  |     name: "SX127x Button" | ||||||
|  |     on_press: | ||||||
|  |       then: | ||||||
|  |         - sx127x.set_mode_standby | ||||||
|  |         - sx127x.run_image_cal | ||||||
|  |         - sx127x.set_mode_tx | ||||||
|  |         - sx127x.set_mode_sleep | ||||||
|  |         - sx127x.set_mode_rx | ||||||
|  |         - sx127x.send_packet: | ||||||
|  |             data: [0xC5, 0x51, 0x78, 0x82, 0xB7, 0xF9, 0x9C, 0x5C] | ||||||
							
								
								
									
										9
									
								
								tests/components/sx127x/test.esp32-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/components/sx127x/test.esp32-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO5 | ||||||
|  |   mosi_pin: GPIO27 | ||||||
|  |   miso_pin: GPIO19 | ||||||
|  |   cs_pin: GPIO18 | ||||||
|  |   rst_pin: GPIO23 | ||||||
|  |   dio0_pin: GPIO26 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										9
									
								
								tests/components/sx127x/test.esp32-c3-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/components/sx127x/test.esp32-c3-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO5 | ||||||
|  |   mosi_pin: GPIO18 | ||||||
|  |   miso_pin: GPIO19 | ||||||
|  |   cs_pin: GPIO1 | ||||||
|  |   rst_pin: GPIO2 | ||||||
|  |   dio0_pin: GPIO3 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										9
									
								
								tests/components/sx127x/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/components/sx127x/test.esp32-c3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO5 | ||||||
|  |   mosi_pin: GPIO18 | ||||||
|  |   miso_pin: GPIO19 | ||||||
|  |   cs_pin: GPIO1 | ||||||
|  |   rst_pin: GPIO2 | ||||||
|  |   dio0_pin: GPIO3 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										9
									
								
								tests/components/sx127x/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/components/sx127x/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO5 | ||||||
|  |   mosi_pin: GPIO27 | ||||||
|  |   miso_pin: GPIO19 | ||||||
|  |   cs_pin: GPIO18 | ||||||
|  |   rst_pin: GPIO23 | ||||||
|  |   dio0_pin: GPIO26 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										9
									
								
								tests/components/sx127x/test.esp8266-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/components/sx127x/test.esp8266-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO5 | ||||||
|  |   mosi_pin: GPIO13 | ||||||
|  |   miso_pin: GPIO12 | ||||||
|  |   cs_pin: GPIO1 | ||||||
|  |   rst_pin: GPIO2 | ||||||
|  |   dio0_pin: GPIO3 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
							
								
								
									
										9
									
								
								tests/components/sx127x/test.rp2040-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/components/sx127x/test.rp2040-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | substitutions: | ||||||
|  |   clk_pin: GPIO2 | ||||||
|  |   mosi_pin: GPIO3 | ||||||
|  |   miso_pin: GPIO4 | ||||||
|  |   cs_pin: GPIO5 | ||||||
|  |   rst_pin: GPIO6 | ||||||
|  |   dio0_pin: GPIO7 | ||||||
|  |  | ||||||
|  | <<: !include common.yaml | ||||||
		Reference in New Issue
	
	Block a user