From 177179d8a4cc4b2d733180f2ec991b195ccd3351 Mon Sep 17 00:00:00 2001 From: John Dillenburg Date: Sat, 1 Mar 2025 13:14:31 -0600 Subject: [PATCH] Converted tfmini custom component into an external component --- ADXL345.h | 15 +- external_components/esphome-tfmini/LICENSE | 21 ++ external_components/esphome-tfmini/README.md | 58 ++++++ .../esphome-tfmini/tfmini/__init__.py | 17 ++ .../esphome-tfmini/tfmini/sensor.py | 76 ++++++++ .../esphome-tfmini/tfmini/tfmini.cpp | 112 +++++++++++ .../esphome-tfmini/tfmini/tfmini.h | 41 ++++ garage-door-controller.yaml | 60 +++--- packages/beacon.yaml | 2 - packages/sen0395.yaml | 181 +++++------------- packages/wifi.yaml | 11 -- 11 files changed, 416 insertions(+), 178 deletions(-) create mode 100644 external_components/esphome-tfmini/LICENSE create mode 100644 external_components/esphome-tfmini/README.md create mode 100644 external_components/esphome-tfmini/tfmini/__init__.py create mode 100644 external_components/esphome-tfmini/tfmini/sensor.py create mode 100644 external_components/esphome-tfmini/tfmini/tfmini.cpp create mode 100644 external_components/esphome-tfmini/tfmini/tfmini.h diff --git a/ADXL345.h b/ADXL345.h index 83fd63f..d68a9e2 100644 --- a/ADXL345.h +++ b/ADXL345.h @@ -7,6 +7,7 @@ class ADXL345Sensor : public PollingComponent { public: Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345); Sensor *off_vertical = new Sensor(); + Sensor *jitter = new Sensor(); ADXL345Sensor() : PollingComponent(100) { } @@ -23,8 +24,16 @@ class ADXL345Sensor : public PollingComponent { void update() override { sensors_event_t event; accel.getEvent(&event); - double pitch_amount = atan(event.acceleration.y / sqrt(pow(event.acceleration.x, 2) + pow(event.acceleration.z, 2))) * 180 / PI; - double roll_amount = atan(-1 * event.acceleration.x / sqrt(pow(event.acceleration.y, 2) + pow(event.acceleration.z, 2))) * 180 / PI; - off_vertical->publish_state(max(abs(pitch_amount), abs(roll_amount))); + double pitch_amount = atan(event.acceleration.y / + sqrt(pow(event.acceleration.x, 2) + pow(event.acceleration.z, 2))) * 180 / PI; + double roll_amount = atan(-1 * event.acceleration.x / + sqrt(pow(event.acceleration.y, 2) + pow(event.acceleration.z, 2))) * 180 / PI; + // double pitch_amount = atan2(event.acceleration.y, + // sqrt(pow(event.acceleration.x, 2) + pow(event.acceleration.z, 2))) * 180 / PI; + // double roll_amount = atan2(-1 * event.acceleration.x, + // sqrt(pow(event.acceleration.y, 2) + pow(event.acceleration.z, 2))) * 180 / PI; + off_vertical -> publish_state(max(abs(pitch_amount), abs(roll_amount))); + jitter -> publish_state(abs(event.acceleration.x) + abs(event.acceleration.y) + + abs(event.acceleration.z)); } }; diff --git a/external_components/esphome-tfmini/LICENSE b/external_components/esphome-tfmini/LICENSE new file mode 100644 index 0000000..f7e6893 --- /dev/null +++ b/external_components/esphome-tfmini/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Your Name + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/external_components/esphome-tfmini/README.md b/external_components/esphome-tfmini/README.md new file mode 100644 index 0000000..378e171 --- /dev/null +++ b/external_components/esphome-tfmini/README.md @@ -0,0 +1,58 @@ +# TFMini-S Time of Flight Distance Sensor for ESPHome + +This is an external component for ESPHome that supports the TFMini-S time of flight distance sensor. + +## Installation + +You can install this component in two ways: + +### 1. Using ESPHome external components + +```yaml +external_components: + - source: github://your-username/esphome-tfmini@main + components: [ tfmini ] +``` + +### 2. Manual installation + +Clone this repository into your ESPHome `custom_components` directory: + +```bash +cd /custom_components +git clone https://github.com/your-username/esphome-tfmini.git +``` + +## Configuration + +Add the following to your ESPHome configuration file: + +```yaml +# Example configuration +uart: + tx_pin: GPIO17 + rx_pin: GPIO16 + baud_rate: 115200 + +sensor: + - platform: tfmini + name: "Distance Sensor" + update_interval: 1s +``` + +## Features + +- Measures distance in meters +- Automatic configuration of the TFMini-S sensor +- Signal strength validation +- Temperature monitoring (internal, not exposed yet) + +## Notes + +- The sensor is configured to use the standard 9-byte output format +- Refresh rate is set to 100Hz +- Data is provided in meters with 2 decimal precision + +## License + +This component is licensed under the MIT License. \ No newline at end of file diff --git a/external_components/esphome-tfmini/tfmini/__init__.py b/external_components/esphome-tfmini/tfmini/__init__.py new file mode 100644 index 0000000..1525f88 --- /dev/null +++ b/external_components/esphome-tfmini/tfmini/__init__.py @@ -0,0 +1,17 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.const import CONF_ID + +DEPENDENCIES = ['uart'] +AUTO_LOAD = ['sensor'] + +tfmini_ns = cg.esphome_ns.namespace('tfmini') +TFMiniComponent = tfmini_ns.class_('TFMiniComponent', cg.Component) + +CONFIG_SCHEMA = cv.Schema({ + cv.GenerateID(): cv.declare_id(TFMiniComponent) +}).extend(cv.COMPONENT_SCHEMA) + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) diff --git a/external_components/esphome-tfmini/tfmini/sensor.py b/external_components/esphome-tfmini/tfmini/sensor.py new file mode 100644 index 0000000..f514a4d --- /dev/null +++ b/external_components/esphome-tfmini/tfmini/sensor.py @@ -0,0 +1,76 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor, uart +from esphome.const import ( + CONF_ID, + DEVICE_CLASS_DISTANCE, + DEVICE_CLASS_SIGNAL_STRENGTH, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_METER, + UNIT_CENTIMETER, + UNIT_CELSIUS, + ICON_RULER, + ENTITY_CATEGORY_DIAGNOSTIC, +) + +DEPENDENCIES = ['uart'] + +tfmini_ns = cg.esphome_ns.namespace('tfmini') +TFMiniSensor = tfmini_ns.class_('TFMiniSensor', sensor.Sensor, cg.Component, + uart.UARTDevice) + +CONF_STRENGTH = "strength" +CONF_TEMPERATURE = "temperature" +CONF_DISTANCE_UNIT = "distance_unit" + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + TFMiniSensor, + unit_of_measurement=UNIT_CENTIMETER, # Default to cm instead of meters + accuracy_decimals=0, # Integer precision for cm + device_class=DEVICE_CLASS_DISTANCE, + state_class=STATE_CLASS_MEASUREMENT, + icon=ICON_RULER, + ) + .extend({ + cv.Optional(CONF_DISTANCE_UNIT, default="cm"): cv.enum({ + "cm": "CENTIMETERS", + "m": "METERS", + }), + cv.Optional(CONF_STRENGTH): sensor.sensor_schema( + unit_of_measurement="", + accuracy_decimals=0, + device_class=DEVICE_CLASS_SIGNAL_STRENGTH, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + }) + .extend(uart.UART_DEVICE_SCHEMA) +) + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + await uart.register_uart_device(var, config) + + cg.add(var.set_distance_unit(config[CONF_DISTANCE_UNIT])) + + if config[CONF_DISTANCE_UNIT] == "m": + cg.add(var.set_unit_of_measurement(UNIT_METER)) + cg.add(var.set_accuracy_decimals(2)) + + if CONF_STRENGTH in config: + sens = await sensor.new_sensor(config[CONF_STRENGTH]) + cg.add(var.set_strength_sensor(sens)) + + if CONF_TEMPERATURE in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) + cg.add(var.set_temperature_sensor(sens)) \ No newline at end of file diff --git a/external_components/esphome-tfmini/tfmini/tfmini.cpp b/external_components/esphome-tfmini/tfmini/tfmini.cpp new file mode 100644 index 0000000..3912213 --- /dev/null +++ b/external_components/esphome-tfmini/tfmini/tfmini.cpp @@ -0,0 +1,112 @@ +#include "tfmini.h" +#include + +namespace esphome { +namespace tfmini { + +static const char *const TAG = "tfmini"; +static const uint8_t HEADER = 0x59; // frame header of data package + +void TFMiniSensor::setup() { + this->set_timeout(50, [this]() { this->setup_internal_(); }); +} + +void TFMiniSensor::setup_internal_() { + // Configure standard 9-byte output format (cm) + const uint8_t standard_mode[5] = {0x5A, 0x05, 0x05, 0x01, 0x65}; + this->write_array(standard_mode, 5); + delay(100); + + // Set refresh rate to 100Hz (1000/0x0A = 100) + const uint8_t rate100[6] = {0x5A, 0x06, 0x03, 0x0A, 0x00, 0x6D}; + this->write_array(rate100, 6); + delay(100); + + // Save the settings + const uint8_t save_setting[4] = {0x5A, 0x04, 0x11, 0x6F}; + this->write_array(save_setting, 4); + + // Wait for the sensor to come back online + delay(1000); + + this->flush(); + ESP_LOGD(TAG, "TFMini setup completed"); +} + +void TFMiniSensor::loop() { + while (this->available() >= 9) { + if (this->read() != HEADER) { + continue; + } + + if (this->read() != HEADER) { + continue; + } + + uint8_t data[7]; + if (!this->read_array(data, 7)) { + continue; + } + + // Verify checksum + uint8_t checksum = HEADER + HEADER; + for (size_t i = 0; i < 6; i++) { + checksum += data[i]; + } + + if (checksum != data[6]) { + ESP_LOGW(TAG, "TFMini checksum error"); + continue; + } + + // Extract distance data (first two bytes) + uint16_t distance_cm = data[0] | (data[1] << 8); + // Extract signal strength (next two bytes) + uint16_t strength = data[2] | (data[3] << 8); + // Extract temperature (next two bytes) + float temperature = (data[4] | (data[5] << 8)) / 8.0f - 256.0f; + + // Only publish valid readings + if (strength < 100) { + ESP_LOGW(TAG, "TFMini signal strength too low: %u", strength); + continue; + } + + // Convert to requested unit + float distance_value; + if (this->distance_unit_ == METERS) { + distance_value = distance_cm / 100.0f; + ESP_LOGD(TAG, "Distance: %.2f m, Strength: %u, Temperature: %.1f °C", + distance_value, strength, temperature); + } else { + distance_value = distance_cm; + ESP_LOGD(TAG, "Distance: %d cm, Strength: %u, Temperature: %.1f °C", + distance_cm, strength, temperature); + } + + // Publish all values + this->publish_state(distance_value); + + if (this->strength_sensor_ != nullptr) { + this->strength_sensor_->publish_state(strength); + } + + if (this->temperature_sensor_ != nullptr) { + this->temperature_sensor_->publish_state(temperature); + } + + return; + } +} + +void TFMiniSensor::dump_config() { + ESP_LOGCONFIG(TAG, "TFMini:"); + LOG_SENSOR(" ", "Distance", this); + ESP_LOGCONFIG(TAG, " Distance Unit: %s", this->distance_unit_ == METERS ? "meters" : "centimeters"); + LOG_SENSOR(" ", "Signal Strength", this->strength_sensor_); + LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); + this->check_uart_settings(115200); +} + +} // namespace tfmini +} // namespace esphome \ No newline at end of file diff --git a/external_components/esphome-tfmini/tfmini/tfmini.h b/external_components/esphome-tfmini/tfmini/tfmini.h new file mode 100644 index 0000000..7638f46 --- /dev/null +++ b/external_components/esphome-tfmini/tfmini/tfmini.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include + +namespace esphome { +namespace tfmini { + +enum DistanceUnit { + CENTIMETERS, + METERS +}; + +class TFMiniSensor : public sensor::Sensor, public Component, public uart::UARTDevice { + public: + void setup() override; + void loop() override; + void dump_config() override; + float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; } + + void set_strength_sensor(sensor::Sensor *strength_sensor) { strength_sensor_ = strength_sensor; } + void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; } + void set_distance_unit(const std::string &distance_unit) { + if (distance_unit == "METERS") { + this->distance_unit_ = METERS; + } else { + this->distance_unit_ = CENTIMETERS; + } + } + + protected: + void setup_internal_(); + + sensor::Sensor *strength_sensor_{nullptr}; + sensor::Sensor *temperature_sensor_{nullptr}; + DistanceUnit distance_unit_{CENTIMETERS}; +}; + +} // namespace tfmini +} // namespace esphome \ No newline at end of file diff --git a/garage-door-controller.yaml b/garage-door-controller.yaml index d24faf3..6b38438 100644 --- a/garage-door-controller.yaml +++ b/garage-door-controller.yaml @@ -1,13 +1,15 @@ esphome: name: garage-door-controller friendly_name: Garage door controller - includes: - - TFmini.h packages: beacon: !include { file: packages/beacon.yaml } wifi: !include { file: packages/wifi.yaml, vars: { ssid: "garage-door-controller" }} +external_components: + - source: external_components/esphome-tfmini + components: [ tfmini ] + substitutions: led_count: "60" @@ -15,6 +17,7 @@ esp32: board: esp32dev framework: type: arduino + # Enable logging logger: @@ -50,9 +53,10 @@ switch: restore_mode: ALWAYS_OFF on_turn_on: then: - - delay: 100ms + - delay: 30000ms - switch.turn_off: relay + # configurable distance thresholds number: - platform: template @@ -129,29 +133,25 @@ binary_sensor: #******************** Sensor ********************* sensor: - - platform: custom - lambda: |- - auto distance_sensor = new TFminiSensor(id(uart_bus)); - App.register_component(distance_sensor); - return {distance_sensor}; - sensors: - id: distance_sensor_raw - internal: True - name: "Distance sensor raw" - unit_of_measurement: "cm" - on_value: - then: - - sensor.template.publish: - id: distance_sensor - state: !lambda 'return x;' - - sensor.template.publish: - id: distance_sensor_leds - state: !lambda 'return x;' - - lambda: |- - id(sensor_counter) = id(sensor_counter) + 1; - # - sensor.template.publish: - # id: reading_sensor_counter - # state: !lambda 'return id(reading_counter).state + 1;' + - platform: tfmini + id: distance_sensor_raw + internal: True + distance_unit: cm + name: "Distance sensor raw" + unit_of_measurement: "cm" + on_value: + then: + - sensor.template.publish: + id: distance_sensor + state: !lambda 'return x;' + - sensor.template.publish: + id: distance_sensor_leds + state: !lambda 'return x;' + - lambda: |- + id(sensor_counter) = id(sensor_counter) + 1; + # - sensor.template.publish: + # id: reading_sensor_counter + # state: !lambda 'return id(reading_counter).state + 1;' - platform: template name: "Distance sensor" id: distance_sensor @@ -291,6 +291,13 @@ light: // Measure update rate id(effect_counter) = id(effect_counter) + 1; + // Set safe_zone flag based on distance + if (distance >= min_safe && distance <= max_safe) { + id(safe_zone) = true; + } else { + id(safe_zone) = false; + } + // blink if less than min_safe if (distance < min_safe) { if ((millis() % 1000) < 500) { @@ -305,7 +312,6 @@ light: // solid red in safe zone if (distance < max_safe) { it.all() = Color(255,0,0); - id(safe_zone) = true; return; } diff --git a/packages/beacon.yaml b/packages/beacon.yaml index 0aa7a22..b68e635 100644 --- a/packages/beacon.yaml +++ b/packages/beacon.yaml @@ -14,5 +14,3 @@ time: bluetooth_proxy: -esp32_ble_tracker: - diff --git a/packages/sen0395.yaml b/packages/sen0395.yaml index 09f1257..3c53ce2 100644 --- a/packages/sen0395.yaml +++ b/packages/sen0395.yaml @@ -1,6 +1,5 @@ esphome: - includes: - - leapmmw_sensor.h + comment: Sen0395 # Disable uart logging logger: @@ -8,7 +7,7 @@ logger: level: DEBUG uart: - id: SEN095_UART_BUS + id: SEN0395_UART_BUS rx_pin: ${uart_rx_pin} tx_pin: ${uart_tx_pin} baud_rate: 115200 @@ -17,6 +16,7 @@ uart: parity: NONE dfrobot_sen0395: + - uart_id: SEN0395_UART_BUS binary_sensor: - platform: gpio @@ -26,139 +26,50 @@ binary_sensor: pin: number: ${presence_pin} mode: INPUT_PULLDOWN - # when motion is detected, the radar sensor is on so publish radar state to HA - on_press: - then: - lambda: !lambda |- - if (!id(mmwave_sensor).state) { - id(mmwave_sensor).publish_state(true); - } - -sensor: - - platform: custom - lambda: |- - auto s = new leapmmw(id(SEN095_UART_BUS)); - App.register_component(s); - return {}; - sensors: - -switch: - - platform: template - name: "${device_name_pretty} mmwave_sensor" - id: mmwave_sensor # do not change - entity_category: config - optimistic: true - turn_on_action: - - uart.write: "setUartOutput 1 0" - - delay: 1s - - uart.write: "saveConfig" - - delay: 4s - - uart.write: "sensorStart" - turn_off_action: - - uart.write: "sensorStop" - - delay: 2s - - - platform: template - name: "${device_name_pretty} led" - id: led # do not change - entity_category: config - optimistic: true - turn_on_action: - - switch.turn_off: mmwave_sensor - - delay: 2s - - uart.write: "setLedMode 1 0" - - delay: 3s - - lambda: |- - leapmmw(id(SEN095_UART_BUS)).getmmwConf("getLedMode 1"); - - delay: 2s - - switch.turn_on: mmwave_sensor - turn_off_action: - - switch.turn_off: mmwave_sensor - - delay: 2s - - uart.write: "setLedMode 1 1" - - delay: 3s - - lambda: |- - leapmmw(id(SEN095_UART_BUS)).getmmwConf("getLedMode 1"); - - delay: 2s - - switch.turn_on: mmwave_sensor number: - - platform: template - name: "${device_name_pretty} distance" - id: distance # do not change - entity_category: config - min_value: 0.15 - max_value: 9.45 - step: 0.15 - unit_of_measurement: M - mode: box - lambda: |- - leapmmw(id(SEN095_UART_BUS)).getmmwConf("getRange"); - return {}; - set_action: - - switch.turn_off: mmwave_sensor - - delay: 2s - - uart.write: !lambda - std::string range = "setRange 0 " + str_sprintf("%.2f", x); - return std::vector(range.begin(), range.end()); - - delay: 3s - - switch.turn_on: mmwave_sensor + # - platform: template + # name: "${device_name_pretty} distance" + # id: distance # do not change + # entity_category: config + # min_value: 0.15 + # max_value: 9.45 + # step: 0.15 + # unit_of_measurement: M + # mode: box + # lambda: 'return {};' + # set_action: + # - dfrobot_sen0395.settings: + # detection_segments: + # - !lambda |- + # return 0; + # - !lambda |- + # return id(distance).state; - - platform: template - name: "${device_name_pretty} latency" - id: latency # do not change - entity_category: config - min_value: 1 - max_value: 600 - lambda: |- - leapmmw(id(SEN095_UART_BUS)).getmmwConf("getLatency"); - return {}; - step: 1 - unit_of_measurement: s - mode: box - set_action: - - switch.turn_off: mmwave_sensor - - delay: 2s - - uart.write: !lambda - std::string setL = "setLatency 0.1 " + str_sprintf("%.0f", x); - return std::vector(setL.begin(), setL.end()); - - delay: 3s - - switch.turn_on: mmwave_sensor + # - platform: template + # name: "${device_name_pretty} latency" + # id: latency # do not change + # entity_category: config + # min_value: 1 + # max_value: 600 + # step: 1 + # unit_of_measurement: s + # mode: box + # lambda: 'return {};' + # set_action: + # - dfrobot_sen0395.settings: + # output_latency: + # delay_after_detect: 0s + # delay_after_disappear: !lambda 'return id(latency).state * 1.0f;' - - platform: template - name: "${device_name_pretty} sensitivity" - id: sensitivity # do not change - entity_category: config - min_value: 0 - max_value: 9 - lambda: |- - leapmmw(id(SEN095_UART_BUS)).getmmwConf("getSensitivity"); - return {}; - step: 1 - set_action: - - switch.turn_off: mmwave_sensor - - delay: 2s - - uart.write: !lambda - std::string mss = "setSensitivity " + to_string((int)x); - return std::vector(mss.begin(), mss.end()); - - delay: 3s - - switch.turn_on: mmwave_sensor - -button: - - platform: restart - name: Restart_ESP_${device_name} - entity_category: diagnostic - on_press: - - uart.write: - id: SEN095_UART_BUS - data: "resetSystem 0" - - - platform: template - name: factory_reset_mmwMCU_${device_name} - id: factory_reset_mmwMCU - entity_category: diagnostic - on_press: - - switch.turn_off: mmwave_sensor - - delay: 2s - - uart.write: "resetCfg" - - delay: 3s \ No newline at end of file + # - platform: template + # name: "${device_name_pretty} sensitivity" + # id: sensitivity # do not change + # entity_category: config + # min_value: 0 + # max_value: 9 + # step: 1 + # lambda: 'return {};' + # set_action: + # - dfrobot_sen0395.settings: + # sensitivity: !lambda 'return (int32_t)id(sensitivity).state;' diff --git a/packages/wifi.yaml b/packages/wifi.yaml index 4e37678..21cf1a4 100644 --- a/packages/wifi.yaml +++ b/packages/wifi.yaml @@ -4,14 +4,3 @@ wifi: ssid: !secret wifi_ssid password: !secret wifi_password - # Enable fallback hotspot (captive portal) in case wifi connection fails - ap: - ssid: "${ssid}" - password: !secret ap_and_web_server_password - -web_server: - auth: - username: johndillenburg - password: !secret ap_and_web_server_password - -captive_portal: