Tutoriel détecteur LD2450 esphome

Bonjour selecus, et bien j’ai mon détecteur dans ma veranda pour allumer les lumières automatiquement quand je passe dans celle-ci. Il n’y a pas de porte mais une grande ouverture entre salon et veranda. Le détecteur est en hauteur sur un rebord presque au plafond de la veranda. De l’autre côté du mur se trouve le salon. Lorsque je me déplace dans le salon il me détecte…

Je crois comprendre… Au vu de ce que tu me décris, je suppose qu’il y a un rebond sur le fond de ta véranda qui revient dans le salon. Si tu veux plus d’informations, lis la page 18 du manuel dont je t’ai partagé le lien.

Je vais faire une hypothèse pour pouvoir m’expliquer. Je vais imaginer que tu as 2 mètres entre ton capteur et le mur de la véranda. Puisque le détecteur peut aller au plus loin jusqu’à 8 mètres si ton salon fait au minimum 4 mètres tu seras encore détecté dedans.

Mais il y a une solution puisque le LD2450 est capable de te donner une position de détection, il faut que tu créais une zone pour ta véranda. Il faudra que tu fasses des tests pour savoir si ta zone doit faire 2 mètres ou 4 mètres mais tout ce qui ira au-delà de la ne doit pas être pris en compte, c’est certain.

Bonjour Selecus, Sii le yaml est dans l’ESP32, ou met-on le fichier zone.h?

ici
image

1 « J'aime »

Personne n’a tenté d’adapter ce montage pour utiliser ZigBee ?
Il paraît qu’il existe des ESP32 qui ont intégré ZigBee nativement maintenant (H2, C6…).

Salut,

Oui effectivement, mais pas encore supporté par ESPHome… Enfin, selon mes dernières infos qui ne sont peut-être pas à jour :blush:
Sans parler d’un montage avec un LD2450, il y a plusieurs sujets sur HACF qui en parle.
Moteur de recherche avec « esp zigbee » …

1 « J'aime »

Bonjour Selecus … J’utilise ce module depuis bientôt 2 mois et tout marche bien. Merci encore pour ce gros travaille au niveau de la programmation de l’ESP. Pourtant, aujourd’hui j’ai jeté un coup d’œil sur les log de mon home assistant (ce que je n’avais pas fait depuis un bon moment!) et me suis aperçu que j’avais un grand nombre d’erreur dont je donne quelques exemples ci-dessous. En fait il y a une erreur pour toutes les entités (numbers, switches, sensors, binary sensors et text). Ces erreurs n’ont pas l’air d’affecter le fonctionnement, mais pour autant ca n’est pas normal. Est-ce que ceci te dis quelque chose??
Merci d’avance pour ton aide.

2024-11-03 09:17:17.605 ERROR (MainThread) [homeassistant.components.number] Platform esphome does not generate unique IDs. ID C8:F0:9E:F2:8B:60-number-_any_presence_timeout is already used by number.esp4_salon_any_presence_timeout - ignoring number.esp4-salon__any_presence_timeout

2024-11-03 09:17:17.606 ERROR (MainThread) [homeassistant.components.number] Platform esphome does not generate unique IDs. ID C8:F0:9E:F2:8B:60-number-_zone1_timeout is already used by number.esp4_salon_zone1_timeout - ignoring number.esp4-salon__zone1_timeout

2024-11-03 09:17:17.606 ERROR (MainThread) [homeassistant.components.number] Platform esphome does not generate unique IDs. ID C8:F0:9E:F2:8B:60-number-_zone2_timeout is already used by number.esp4_salon_zone2_timeout - ignoring number.esp4-salon__zone2_timeout

2024-11-03 09:17:17.606 ERROR (MainThread) [homeassistant.components.number] Platform esphome does not generate unique IDs. ID C8:F0:9E:F2:8B:60-number-_zone3_timeout is already used by number.esp4_salon_zone3_timeout - ignoring number.esp4-salon__zone3_timeout

2024-11-03 09:17:17.606 ERROR (MainThread) [homeassistant.components.number] Platform esphome does not generate unique IDs. ID C8:F0:9E:F2:8B:60-number-_zone1_x is already used by number.esp4_salon_zone1_x - ignoring number.esp4-salon__zone1_x

2024-11-03 09:17:17.606 ERROR (MainThread) [homeassistant.components.number] Platform esphome does not generate unique IDs. ID C8:F0:9E:F2:8B:60-number-_zone1_y is already used by number.esp4_salon_zone1_y - ignoring number.esp4-salon__zone1_y

2024-11-03 09:17:17.606 ERROR (MainThread) [homeassistant.components.number] Platform esphome does not generate unique IDs. ID C8:F0:9E:F2:8B:60-number-_zone1_height is already used by number.esp4_salon_zone1_height - ignoring number.esp4-salon__zone1_height

2024-11-03 09:17:17.606 ERROR (MainThread) [homeassistant.components.number] Platform esphome does not generate unique IDs. ID C8:F0:9E:F2:8B:60-number-_zone1_width is already used by number.esp4_salon_zone1_width - ignoring number.esp4-salon__zone1_width

2024-11-03 09:17:17.606 ERROR (MainThread) [homeassistant.components.number] Platform esphome does not generate unique IDs. ID C8:F0:9E:F2:8B:60-number-_zone2_x is already used by number.esp4_salon_zone2_x - ignoring number.esp4-salon__zone2_x

Salut Pierre,
en regardant en détail ton log il semble que tu aies créé deux appareils nommé « esp4 ». L’un est ignoré et l’autre pas.

  • number.esp4_salon_zone1_timeout
  • number.esp4-salon__zone1_timeout (ignoré)
    Je te recommande de chercher les entités ignorées et de les supprimer

[quote=« Lepelot, post:250, topic:33251 »]
salon__
[/quote

Ah oui, ca c’est intéressant … j’ai cherché dans la liste des entities , mais je n’ai pas trouvé number.esp4-salon__zone1_timeout (ignoré) … Oui peut-elle bien être ??

et dans les appareils combien as-tu de « esp4-salon » ?

Un seul dans les appareils… mais c’est vrai que j’ai changé le nom plusieurs fois pendant l’expérimentation.

La, je sèche… Désolé

Ok, merci.

J’ai installer l’intégration watchman qui permet de faire du nettoyage sur les entités; elle m’a bien trouvé des erreurs, mais malheureusement aucune concernant l’esp4-salon .

Bonjour,
J’ai vu que ESPHome n’as toujours pas inclus le LD2450 dans la doc et j’ai vu pas mal de projets GitHub le concernant mais je ne sais pas le quel choisir… Sauriez-vous quel code fonctionne le mieux actuellement ? Je me demandais aussi ce qui faisait traîner son inclusion dans la doc…
Merci.

Salut a tous
Je me permets de venir vers vous car je viens seulement d arriver a pouvoir téléverser sur mon ESP32S2 mini après des jours de durs labeurs !
Encore un grand MERCI @WarC0zes pour son aide et sa patience !
Je ne suis pas encore sur HA mais sur JEEDOM donc j espère que vous accepterez tout de même de m aider :upside_down_face:!
J avais précédemment essayé un code sur un esp32vroom de ce tuto https://www.youtube.com/watch?v=y7f5nJClV_I
Qui m indiquait également les status des cibles :" static, mouement et appoche "
En téléversant le code de ce topic ; je n ai plus cet état et j ai de grosses latence par apport aux cibles voir parfois 1 cible prise en compte sur 3 ?!
Y a t il un paramètre a modifier ?! Je me suis mis sur les pins Rx :18 et Tx :33
Je vous poste le code !

esp32:
  board: lolin_s2_mini
  framework:
    type: arduino
mqtt:
  topic_prefix: ESPHOME_LD2450_boite_lettres
  discovery: false
  broker: 192.168.1.12
  port: 1883
  username: jeedom
  password: pw
  discovery_prefix: homeassistant
  
# Enable logging
logger:

# Enable Home Assistant API

ota:
  - platform: esphome
    password: "8a93a89b3a9ef669596ec18240f16f07"

wifi:
  ssid: Wifi_NyG_2.4
  password: rachida.xxxxxxxxx

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Capteur-Boite-Lettres"
    password: "mYNmLdmsxjqD"
    
# Optional manual IP
  manual_ip:
    static_ip: 192.168.1.238
    gateway: 192.168.1.1
    subnet: 255.255.255.0 
    
web_server:
  port: 80
  
captive_portal:
    
   # LD2450
substitutions:
  devicename: ld2450
  upper_devicename: "Hi-Link LD2450"

esphome:
  name: capteur-boite-lettres
  friendly_name: capteur-boite-lettres-esp32minis2

  includes:
    - components/ld2450_uart.h
  on_boot:
    priority: -100
    # ...
    then:
      - lambda: 'static_cast<LD2450 *>(ld2450)->getInfo();'
      - lambda: id(tracking_mode).publish_state("Multiple");

uart:
  id: uart_ld2450
  tx_pin: GPIO18
  rx_pin: GPIO33
  baud_rate: 256000
  parity: NONE
  stop_bits: 1
#  debug:
#    direction: BOTH
#    dummy_receiver: false

custom_component:
  - lambda: |-
      return {new LD2450(id(uart_ld2450))};
    components:
      - id: ld2450

binary_sensor:
  - platform: custom
    lambda: |-
      auto uart_component = static_cast<LD2450 *>(ld2450);
      return {uart_component->lastCommandSuccess, uart_component->configMode, uart_component->bluetoothState};
    binary_sensors:
      - name: "Last Command Success"
        id: binary_sensor_command_state
        internal: true
      - name: "Config Mode"
        icon: mdi:cog
        id: binary_sensor_config_mode
      - name: "Bluetooth State"
        icon: mdi:bluetooth
        id: binary_sensor_bluetooth_state
        internal: true

button:
  - platform: template
    name: "Reboot LD2450"
    on_press:
      - lambda: 'static_cast<LD2450 *>(ld2450)->reboot();'
  - platform: template
    name: "Factory Reset LD2450"
    on_press:
      - lambda: 'static_cast<LD2450 *>(ld2450)->factoryReset();'
  - platform: template
    name: "Single Target Tracking"
    on_press:
      - lambda: 'static_cast<LD2450 *>(ld2450)->setSingle();'
  - platform: template
    name: "Multiple Targets Tracking"
    on_press:
      - lambda: 'static_cast<LD2450 *>(ld2450)->setMultiple();'
  - platform: template
    name: "Get Zones Information"
    on_press:
      - lambda: 'static_cast<LD2450 *>(ld2450)->getZone();'
  - platform: template
    name: "Set Zones Information"
    on_press:
      lambda: |-
        int type = 0;
        if (id(zone_type).state == "Disable Zone Filter") {
          type = 0;
        } else if (id(zone_type).state == "Only Detect Configured Zone") {
          type = 1;
        } else if (id(zone_type).state == "Not Detect Configured Zone") {
          type = 2;
        }
        static_cast<LD2450 *>(ld2450)->setZone(type, id(zone1_x1).state * 10, id(zone1_y1).state * 10, id(zone1_x2).state * 10, id(zone1_y2).state * 10, id(zone2_x1).state * 10, id(zone2_y1).state * 10, id(zone2_x2).state * 10, id(zone2_y2).state * 10, id(zone2_x1).state * 10, id(zone2_y1).state * 10, id(zone2_x2).state * 10, id(zone2_y2).state * 10);

number:
  - platform: template
    name: "Zone1 X1"
    id: zone1_x1
    icon: mdi:align-horizontal-left
    min_value: -100
    max_value: 100
    step: 1
    optimistic: true
  - platform: template
    name: "Zone1 Y1"
    id: zone1_y1
    icon: mdi:align-horizontal-distribute
    min_value: -100
    max_value: 100
    step: 1
    optimistic: true
  - platform: template
    name: "Zone1 X2"
    id: zone1_x2
    icon: mdi:align-horizontal-right
    min_value: -100
    max_value: 100
    step: 1
    optimistic: true
  - platform: template
    name: "Zone1 Y2"
    id: zone1_y2
    icon: mdi:align-horizontal-distribute
    min_value: -100
    max_value: 100
    step: 1
    optimistic: true
  - platform: template
    name: "Zone2 X1"
    id: zone2_x1
    icon: mdi:align-horizontal-left
    min_value: -100
    max_value: 100
    step: 1
    optimistic: true
  - platform: template
    name: "Zone2 Y1"
    id: zone2_y1
    icon: mdi:align-horizontal-distribute
    min_value: -100
    max_value: 100
    step: 1
    optimistic: true
  - platform: template
    name: "Zone2 X2"
    id: zone2_x2
    icon: mdi:align-horizontal-right
    min_value: -100
    max_value: 100
    step: 1
    optimistic: true
  - platform: template
    name: "Zone2 Y2"
    id: zone2_y2
    icon: mdi:align-horizontal-distribute
    min_value: -100
    max_value: 100
    step: 1
    optimistic: true
  - platform: template
    name: "Zone3 X1"
    id: zone3_x1
    icon: mdi:align-horizontal-left
    min_value: -100
    max_value: 100
    step: 1
    optimistic: true
  - platform: template
    name: "Zone3 Y1"
    id: zone3_y1
    icon: mdi:align-horizontal-distribute
    min_value: -100
    max_value: 100
    step: 1
    optimistic: true
  - platform: template
    name: "Zone3 X2"
    id: zone3_x2
    icon: mdi:align-horizontal-right
    min_value: -100
    max_value: 100
    step: 1
    optimistic: true
  - platform: template
    name: "Zone3 Y2"
    id: zone3_y2
    icon: mdi:align-horizontal-distribute
    min_value: -100
    max_value: 100
    step: 1
    optimistic: true

select:
  - platform: template
    name: "Template select"
    id: zone_type
    optimistic: true
    options:
      - Disable Zone Filter
      - Only Detect Configured Zone
      - Not Detect Configured Zone

sensor:
  - platform: custom
    lambda: |-
      auto uart_component = static_cast<LD2450 *>(ld2450);
      return {uart_component->target1Resolution, uart_component->target1Speed, uart_component->target1X, uart_component->target1Y, uart_component->target2Resolution, uart_component->target2Speed, uart_component->target2X, uart_component->target2Y, uart_component->target3Resolution, uart_component->target3Speed, uart_component->target3X, uart_component->target3Y, uart_component->targets, uart_component->zoneType, uart_component->zone1X1, uart_component->zone1Y1, uart_component->zone1X2, uart_component->zone1Y2, uart_component->zone2X1, uart_component->zone2Y1, uart_component->zone2X2, uart_component->zone2Y2, uart_component->zone3X1, uart_component->zone3Y1, uart_component->zone3X2, uart_component->zone3Y2
      };
    sensors:
      - name: "Target1 Resolution"
        unit_of_measurement: "nm"
        accuracy_decimals: 0
        icon: mdi:artboard
      - name: "Target1 Speed"
        unit_of_measurement: "cm/s"
        accuracy_decimals: 0
        icon: mdi:speedometer
      - name: "Target1 X"
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:map-marker-right
      - name: "Target1 Y"
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:map-marker-down
      - name: "Target2 Resolution"
        unit_of_measurement: "nm"
        accuracy_decimals: 0
        icon: mdi:artboard
      - name: "Target2 Speed"
        unit_of_measurement: "cm/s"
        accuracy_decimals: 0
        icon: mdi:speedometer
      - name: "Target2 X"
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:map-marker-right
      - name: "Target2 Y"
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:map-marker-down
      - name: "Target3 Resolution"
        unit_of_measurement: "nm"
        accuracy_decimals: 0
        icon: mdi:artboard
      - name: "Target3 Speed"
        unit_of_measurement: "cm/s"
        accuracy_decimals: 0
        icon: mdi:speedometer
      - name: "Target3 X"
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:map-marker-right
      - name: "Target3 Y"
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:map-marker-down
      - name: "Targets"
      - name: "Zone Type"
        id: zonetype
        icon: mdi:tangram
        internal: true
        on_value:
          then:
            lambda: |-
              if (id(zonetype).state == 0) {
                id(zone_type).publish_state("Disable Zone Filter");
              } else if (id(zonetype).state == 1) {
                id(zone_type).publish_state("Only Detect Configured Zone");
              } else if (id(zonetype).state == 2) {
                id(zone_type).publish_state("Not Detect Configured Zone");
              }
      - name: "Zone1 X1"
        id: zone1x1
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:align-horizontal-left
        internal: true
        on_value:
          then:
            - lambda: id(zone1_x1).publish_state(id(zone1x1).state);
      - name: "Zone1 Y1"
        id: zone1y1
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:align-horizontal-distribute
        internal: true
        on_value:
          then:
            - lambda: id(zone1_y1).publish_state(id(zone1y1).state);
      - name: "Zone1 X2"
        id: zone1x2
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:align-horizontal-right
        internal: true
        on_value:
          then:
            - lambda: id(zone1_x2).publish_state(id(zone1x2).state);
      - name: "Zone1 Y2"
        id: zone1y2
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:align-horizontal-distribute
        internal: true
        on_value:
          then:
            - lambda: id(zone1_y2).publish_state(id(zone1y2).state);
      - name: "Zone2 X1"
        id: zone2x1
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:align-horizontal-left
        internal: true
        on_value:
          then:
            - lambda: id(zone2_x1).publish_state(id(zone2x1).state);
      - name: "Zone2 Y1"
        id: zone2y1
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:align-horizontal-distribute
        internal: true
        on_value:
          then:
            - lambda: id(zone2_y1).publish_state(id(zone2y1).state);
      - name: "Zone2 X2"
        id: zone2x2
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:align-horizontal-right
        internal: true
        on_value:
          then:
            - lambda: id(zone2_x2).publish_state(id(zone2x2).state);
      - name: "Zone2 Y2"
        id: zone2y2
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:align-horizontal-distribute
        internal: true
        on_value:
          then:
            - lambda: id(zone2_y2).publish_state(id(zone2y2).state);
      - name: "Zone3 X1"
        id: zone3x1
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:align-horizontal-left
        internal: true
        on_value:
          then:
            - lambda: id(zone3_x1).publish_state(id(zone3x1).state);
      - name: "Zone3 Y1"
        id: zone3y1
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:align-horizontal-distribute
        internal: true
        on_value:
          then:
            - lambda: id(zone3_y1).publish_state(id(zone3y1).state);
      - name: "Zone3 X2"
        id: zone3x2
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:align-horizontal-right
        internal: true
        on_value:
          then:
            - lambda: id(zone3_x2).publish_state(id(zone3x2).state);
      - name: "Zone3 Y2"
        id: zone3y2
        unit_of_measurement: "cm"
        accuracy_decimals: 0
        icon: mdi:align-horizontal-distribute
        internal: true
        on_value:
          then:
            - lambda: id(zone3_y2).publish_state(id(zone3y2).state);

switch:
  - platform: template
    name: "Config Mode"
    lambda: |-
      if (id(binary_sensor_config_mode).state) {
        return true;
      } else {
        return false;
      }
    turn_on_action:
      - lambda: 'static_cast<LD2450 *>(ld2450)->setConfigMode(true);'
    turn_off_action:
      - lambda: 'static_cast<LD2450 *>(ld2450)->setConfigMode(false);'
  - platform: template
    name: "Bluetooth Function"
    lambda: |-
      if (id(binary_sensor_bluetooth_state).state) {
        return true;
      } else {
        return false;
      }
    icon: mdi:bluetooth
    turn_on_action:
      - lambda: 'static_cast<LD2450 *>(ld2450)->setBluetooth(true);'
    turn_off_action:
      - lambda: 'static_cast<LD2450 *>(ld2450)->setBluetooth(false);'

text_sensor:
  - platform: custom
    lambda: |-
      auto uart_component = static_cast<LD2450 *>(ld2450);
      return { uart_component->macAddress, uart_component->fwVersion, uart_component->trackingMode
      };
    text_sensors:
      - name: "Mac Address"
        icon: mdi:puzzle
      - name: "Firmware Versoin"
        icon: mdi:new-box
      - name: "Tracking Mode"
        icon: mdi:radar
        id: tracking_mode  
     

En vous remerciant par avance
Bonne journée a tous



Je passe par l adress ip pour le moment puis je passerai via Jeedom en mqtt

Salut a tous
Pas de retour concernant un code qui serait le plus fonctionnel possible ?!
Car diverses options non présente dans le code donné sur le tuto comme cible en (mouvement,static,en approche) qui étaient présentes dans le code donné dans le lien précédemment envoyés ?!
Et surtout le souci qu il ne détecte qu une cible sur 3 avec un manque de fiabilité évident !
En vous remerciant par avance pour vos retours

1 « J'aime »

Bonjour,

je viens justement d’en mettre un en route avec un esp32 S2 et un LD2450.

En revanche généralement je le faisais avec un esp32 dev kit v1 avec les GPIO 16 et 17. Juste parce que j’avais en stock. Et comme je n’en ai plus j’ai pris des esp32 S2 pour le coté usb-c et carte plus petite.

Je n’ai pas réussi avec c’est GPIO 16 et 17 que j’utilisai normalement, donc j’ai pris les 18 et 33.

Je note aussi que ça à l’air moins stable/précis que ceux que j’ai déjà. Aucune idée du pourquoi, si le capteur 2450 est moins bon ce coup ci ou si ça marche moins bien avec un S2.

Je ne suis pas convaincu de la combinaison… si quelqu’un a une idée…

Je te mets quand même le code fonctionnel repris de la video de ArminasTV qui me remonte les infos sur mon HA et que tu peux voir directement en te connectant dessus. (enfin a peu près, avec adaptation à l’arrache en 10min, commenté ce qui bloquait, etc …)

#https://github.com/Emile86/HLK-2450/blob/main/2450.yaml
#https://community.home-assistant.io/t/hlk-ld2450-initial-experiments-to-connect-to-homeassistant/578878/185?page=10
esphome:
  name: esphome-web-9134d4
  comment: Screek Human Sensor 2A
  friendly_name: ESPPresence1
  #name_add_mac_suffix: True
  platformio_options:
    board_build.flash_mode: dio
    # board_build.f_cpu: 80000000L
  project: 
    name: Screek.Human_Presence_Sensor
    version: 2A
  on_boot:
    #- priority: 100
    #  then:
    #    lambda: |-
    #      id(cpu_speed) = ESP.getCpuFreqMHz();
    - priority: -200
      then:
        lambda: |-
          id(zone1_target_exsits).publish_state(false);
          id(zone2_target_exsits).publish_state(false);
          id(zone3_target_exsits).publish_state(false);
          id(zone_ex1_target_exsits).publish_state(false);

preferences:
    flash_write_interval: 5s

external_components:
  - source:
      type: git
      url: https://github.com/screekworkshop/custom_components_support_for_screek_2a
      ref: main
    components: [esp32, uart]
  
esp32:
  board: lolin_s2_mini
  framework:
    type: arduino

globals:
  #- id: cpu_speed
  #  type: int
  #  restore_value: no
  #  initial_value: '0'
  - id: last_update_ld2450
    type: unsigned long
    restore_value: no
    initial_value: '0'
  - id: init_zone_publish
    type: bool
    restore_value: no
    initial_value: "false"
  - id: last_illuminance
    type: float
    restore_value: no
    initial_value: "-1"
  - id: last_illuminance_timestamp
    type: int
    restore_value: no
    initial_value: "-1"

improv_serial:
  
logger:

debug:
  update_interval: 30s

api:

ota:
  platform: esphome
  # use your own ota password plz. this is a words by Socrates.
  #password: !secret ota_password
  #safe_mode: False

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
   # Optional manual IP
  #manual_ip:
  #  static_ip: 192.168.50.211
  #  gateway: 192.168.50.1
  #  subnet: 255.255.255.0
  power_save_mode: LIGHT
  reboot_timeout: 10min
  ap:
    ssid: "HUMAN-SENSOR 2A"

captive_portal:

web_server:
  port: 80


text_sensor:
  - platform: debug
    reset_reason:
      name: "ESP Reset Reason"
      icon: mdi:anchor
      disabled_by_default: True
  - platform: wifi_info
    ip_address:
      name: ESP IP Address
      entity_category: "diagnostic"
      disabled_by_default: True
      icon: mdi:ip-network
    mac_address:
      name: ESP MAC
      entity_category: "diagnostic"
      icon: mdi:ip-network
      disabled_by_default: True
  - platform: template
    name: "Zone1 Info"
    id: tips_zone1_conf
    icon: mdi:information-outline
    entity_category: config
    lambda: |-
      return {"Configure below" };
    update_interval: 1000s
  - platform: template
    name: "Zone2 Info"
    id: tips_zone2_conf
    icon: mdi:information-outline
    entity_category: config
    lambda: |-
      return {"Configure below" };
    update_interval: 1000s
  - platform: template
    name: "Zone3 Info"
    id: tips_zone3_conf
    icon: mdi:information-outline
    entity_category: config
    lambda: |-
      return {"Configure below" };
    update_interval: 1000s
  - platform: template
    name: "Zout1 Info"
    id: tips_zone_ex1_conf
    icon: mdi:information-outline
    entity_category: config
    lambda: |-
      return {"Zone Exclusion 1" };
    update_interval: 1000s
  - platform: template
    name: "Any-Presence Info"
    id: tips_any_presence_conf
    icon: mdi:information-outline
    entity_category: config
    lambda: |-
      return {"Any Presence Config" };
    update_interval: 1000s
  - platform: template
    name: "Target1 Direction"
    id: target1_direction
    icon: mdi:directions
  - platform: template
    name: "Target2 Direction"
    id: target2_direction
    icon: mdi:directions
  - platform: template
    name: "Target3 Direction"
    id: target3_direction
    icon: mdi:directions
  - platform: template
    name: "Target1 Position"
    id: target1_position
    icon: mdi:directions
  - platform: template
    name: "Target2 Position"
    id: target2_position
    icon: mdi:directions
  - platform: template
    name: "Target3 Position"
    id: target3_position
    icon: mdi:directions

number:
  - platform: template
    name: "Any Presence Timeout"
    id: any_presence_timeout
    min_value: 0
    max_value: 600
    mode: box
    device_class: duration
    entity_category: config
    unit_of_measurement: s
    icon: mdi:timer-off
    step: 1
    optimistic: True
    initial_value: 0
    restore_value: True
  - platform: template
    name: "Zone1 Timeout"
    id: zone1_x_timeout
    min_value: 0
    max_value: 600
    mode: box
    device_class: duration
    entity_category: config
    unit_of_measurement: s
    icon: mdi:timer-off
    step: 1
    optimistic: True
    initial_value: 0
    restore_value: True
  - platform: template
    name: "Zone2 Timeout"
    id: zone2_x_timeout
    min_value: 0
    max_value: 600
    mode: box
    device_class: duration
    entity_category: config
    unit_of_measurement: s
    icon: mdi:timer-off
    step: 1
    optimistic: True
    initial_value: 0
    restore_value: True
  - platform: template
    name: "Zone3 Timeout"
    id: zone3_x_timeout
    min_value: 0
    max_value: 600
    mode: box
    device_class: duration
    entity_category: config
    unit_of_measurement: s
    icon: mdi:timer-off
    step: 1
    optimistic: True
    initial_value: 0
    restore_value: True
  # Zone 1
  - platform: template
    name: Zone1 X-Begin
    id: zone1_x_begin
    min_value: -4000
    max_value: 4000
    mode: box
    device_class: distance
    entity_category: config
    unit_of_measurement: mm
    icon: mdi:arrow-left-bold
    step: 10
    optimistic: True
    initial_value: 0
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zone1_vaild
  - platform: template
    name: Zone1 X-End
    id: zone1_x_end
    mode: box
    min_value: -4000
    max_value: 4000
    device_class: distance
    unit_of_measurement: mm
    entity_category: config
    icon: mdi:arrow-right-bold
    step: 10
    initial_value: 0
    optimistic: True
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zone1_vaild
  - platform: template
    name: Zone1 Y-Begin
    id: zone1_y_begin
    mode: box
    min_value: 0
    max_value: 6000
    device_class: distance
    entity_category: config
    icon: mdi:arrow-up-bold
    unit_of_measurement: mm
    step: 10
    initial_value: 0
    optimistic: True
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zone1_vaild
  - platform: template
    name: Zone1 Y-End
    id: zone1_y_end
    icon: mdi:arrow-down-bold
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    entity_category: config
    device_class: distance
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zone1_vaild
  
  # Zone 2
  - platform: template
    name: Zone2 X-Begin
    id: zone2_x_begin
    min_value: -4000
    max_value: 4000
    mode: box
    device_class: distance
    entity_category: config
    unit_of_measurement: mm
    icon: mdi:arrow-left-bold
    step: 10
    optimistic: True
    initial_value: 0
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zone2_vaild
  - platform: template
    name: Zone2 X-End
    id: zone2_x_end
    mode: box
    min_value: -4000
    max_value: 4000
    device_class: distance
    unit_of_measurement: mm
    entity_category: config
    icon: mdi:arrow-right-bold
    step: 10
    initial_value: 0
    optimistic: True
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zone2_vaild
  - platform: template
    name: Zone2 Y-Begin
    id: zone2_y_begin
    mode: box
    min_value: 0
    max_value: 6000
    device_class: distance
    entity_category: config
    icon: mdi:arrow-up-bold
    unit_of_measurement: mm
    step: 10
    initial_value: 0
    optimistic: True
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zone2_vaild
  - platform: template
    name: Zone2 Y-End
    id: zone2_y_end
    icon: mdi:arrow-down-bold
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    entity_category: config
    device_class: distance
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zone2_vaild

  # Zone 3
  - platform: template
    name: Zone3 X-Begin
    id: zone3_x_begin
    min_value: -4000
    max_value: 4000
    mode: box
    device_class: distance
    entity_category: config
    unit_of_measurement: mm
    icon: mdi:arrow-left-bold
    step: 10
    optimistic: True
    initial_value: 0
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zone3_vaild
  - platform: template
    name: Zone3 X-End
    id: zone3_x_end
    mode: box
    min_value: -4000
    max_value: 4000
    device_class: distance
    unit_of_measurement: mm
    entity_category: config
    icon: mdi:arrow-right-bold
    step: 10
    initial_value: 0
    optimistic: True
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zone3_vaild
  - platform: template
    name: Zone3 Y-Begin
    id: zone3_y_begin
    mode: box
    min_value: 0
    max_value: 6000
    device_class: distance
    entity_category: config
    icon: mdi:arrow-up-bold
    unit_of_measurement: mm
    step: 10
    initial_value: 0
    optimistic: True
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zone3_vaild
  - platform: template
    name: Zone3 Y-End
    id: zone3_y_end
    icon: mdi:arrow-down-bold
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    entity_category: config
    device_class: distance
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zone3_vaild
  
  # Zout1
  - platform: template
    name: Zout1 X-Begin
    id: zone_ex1_x_begin
    min_value: -4000
    max_value: 4000
    mode: box
    device_class: distance
    entity_category: config
    unit_of_measurement: mm
    icon: mdi:arrow-left-bold
    step: 10
    optimistic: True
    initial_value: 0
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zout1_vaild
  - platform: template
    name: Zout1 X-End
    id: zone_ex1_x_end
    mode: box
    min_value: -4000
    max_value: 4000
    device_class: distance
    unit_of_measurement: mm
    entity_category: config
    icon: mdi:arrow-right-bold
    step: 10
    initial_value: 0
    optimistic: True
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zout1_vaild
  - platform: template
    name: Zout1 Y-Begin
    id: zone_ex1_y_begin
    mode: box
    min_value: 0
    max_value: 6000
    device_class: distance
    entity_category: config
    icon: mdi:arrow-up-bold
    unit_of_measurement: mm
    step: 10
    initial_value: 0
    optimistic: True
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zout1_vaild
  - platform: template
    name: Zout1 Y-End
    id: zone_ex1_y_end
    icon: mdi:arrow-down-bold
    mode: box
    min_value: 0
    max_value: 6000
    initial_value: 0
    entity_category: config
    device_class: distance
    unit_of_measurement: mm
    step: 10
    optimistic: True
    restore_value: True
    on_value: 
      then:
        - script.execute: check_zout1_vaild

binary_sensor:
  - platform: status
    name: Online
    id: ink_ha_connected
  - platform: template
    name: "Any Presence"
    id: any_target_exsits
    device_class: occupancy
    filters:
      - delayed_off: !lambda |-
          if (!id(init_zone_publish) || !id(zone_fn_enable).state) {
            return 0;
          };
          return id(any_presence_timeout).state * 1000.0;
  - platform: template
    name: "Zone1 Presence"
    id: zone1_target_exsits
    device_class: occupancy
    filters:
      - delayed_off: !lambda |-
          if (!id(init_zone_publish) || !id(zone_fn_enable).state) {
            return 0;
          }
          return id(zone1_x_timeout).state * 1000.0;
  - platform: template
    name: "Zone2 Presence"
    id: zone2_target_exsits
    device_class: occupancy
    filters:
      - delayed_off: !lambda |-
          if (!id(init_zone_publish) || !id(zone_fn_enable).state) {
            return 0;
          }
          return id(zone2_x_timeout).state * 1000.0;
  - platform: template
    name: "Zone3 Presence"
    id: zone3_target_exsits
    device_class: occupancy
    filters:
      - delayed_off: !lambda |-
          if (!id(init_zone_publish) || !id(zone_fn_enable).state) {
            return 0;
          }
          return id(zone3_x_timeout).state * 1000.0;
  - platform: template
    name: "Zout1 Presence"
    id: zone_ex1_target_exsits
    icon: mdi:account-multiple-remove
    device_class: occupancy

script:
  - id: check_zone1_vaild
    then:
      - lambda: |-
          if (id(zone1_x_begin).state > id(zone1_x_end).state){
            id(tips_zone1_conf).publish_state("Err: X-Begin > X-End");
            return;
          }
          if (id(zone1_y_begin).state > id(zone1_y_end).state){
            id(tips_zone1_conf).publish_state("Err: Y-Begin > Y-End");
            return;
          }
          if (id(zone1_x_begin).state == 0 && id(zone1_x_end).state == 0 && id(zone1_y_begin).state == 0 && id(zone1_y_end).state == 0){
            id(tips_zone1_conf).publish_state("Configure below");
            return;
          }

          int x_size = id(zone1_x_end).state - id(zone1_x_begin).state;
          int y_size = id(zone1_y_end).state - id(zone1_y_begin).state;

          char combined[80]; 
          sprintf(combined, "Curr Size: %d x %d", x_size, y_size);
          id(tips_zone1_conf).publish_state(combined);
  - id: check_zone2_vaild
    then:
      - lambda: |-
          if (id(zone2_x_begin).state > id(zone2_x_end).state){
            id(tips_zone2_conf).publish_state("Err: X-Begin > X-End");
            return;
          }
          if (id(zone2_y_begin).state > id(zone2_y_end).state){
            id(tips_zone2_conf).publish_state("Err: Y-Begin > Y-End");
            return;
          }
          if (id(zone2_x_begin).state == 0 && id(zone2_x_end).state == 0 && id(zone2_y_begin).state == 0 && id(zone2_y_end).state == 0){
            id(tips_zone2_conf).publish_state("Configure below");
            return;
          }

          int x_size = id(zone2_x_end).state - id(zone2_x_begin).state;
          int y_size = id(zone2_y_end).state - id(zone2_y_begin).state;

          char combined[80]; 
          sprintf(combined, "Curr Size: %d x %d", x_size, y_size);
          id(tips_zone2_conf).publish_state(combined);
  - id: check_zone3_vaild
    then:
      - lambda: |-
          if (id(zone3_x_begin).state > id(zone3_x_end).state){
            id(tips_zone3_conf).publish_state("Err: X-Begin > X-End");
            return;
          }
          if (id(zone3_y_begin).state > id(zone3_y_end).state){
            id(tips_zone3_conf).publish_state("Err: Y-Begin > Y-End");
            return;
          }
          if (id(zone3_x_begin).state == 0 && id(zone3_x_end).state == 0 && id(zone3_y_begin).state == 0 && id(zone3_y_end).state == 0){
            id(tips_zone3_conf).publish_state("Configure below");
            return;
          }

          int x_size = id(zone3_x_end).state - id(zone3_x_begin).state;
          int y_size = id(zone3_y_end).state - id(zone3_y_begin).state;

          char combined[80]; 
          sprintf(combined, "Curr Size: %d x %d", x_size, y_size);
          id(tips_zone3_conf).publish_state(combined);
  - id: check_zout1_vaild
    then:
      - lambda: |-
          if (id(zone_ex1_x_begin).state > id(zone_ex1_x_end).state){
            id(tips_zone_ex1_conf).publish_state("Err: X-Begin > X-End");
            return;
          }
          if (id(zone_ex1_y_begin).state > id(zone_ex1_y_end).state){
            id(tips_zone_ex1_conf).publish_state("Err: Y-Begin > Y-End");
            return;
          }
          id(tips_zone_ex1_conf).publish_state("Zone Exclusion 1");

sensor:
  #- platform: template
  #  name: "ESP CPU Speed"
  #  accuracy_decimals: 0
  #  icon: mdi:cpu-32-bit
  #  unit_of_measurement: Mhz
  #  disabled_by_default: True
  #  lambda: |-
  #    return (id(cpu_speed));
  #  entity_category: "diagnostic"
  #  update_interval: 600s
  #- platform: template
  #  id: sys_esp_temperature
  #  name: ESP Temperature
  #  lambda: return temperatureRead();
  #  unit_of_measurement: °C
  #  device_class: TEMPERATURE
  #  update_interval: 45s
  #  entity_category: "diagnostic"
  - platform: uptime
    name: ESP Uptime
    id: sys_uptime
    update_interval: 60s
  - platform: wifi_signal 
    name: RSSI
    id: wifi_signal_db
    update_interval: 60s
    entity_category: "diagnostic"
  - platform: template
    id: esp_memory
    icon: mdi:memory
    name: ESP Free Memory
    lambda: return heap_caps_get_free_size(MALLOC_CAP_INTERNAL) / 1024;
    unit_of_measurement: 'kB'
    state_class: measurement
    entity_category: "diagnostic"
    update_interval: 60s

  #-------------------------------------#
  # 高级雷达数据
  - platform: template
    name: "All Target Counts"
    id: all_target_count
    accuracy_decimals: 0
    icon: "mdi:counter"
    unit_of_measurement: "targets"
  - platform: template
    name: "Zone1 Target Counts"
    id: zone1_target_count
    accuracy_decimals: 0
    icon: "mdi:counter"
    unit_of_measurement: "targets"
  - platform: template
    name: "Zone2 Target Counts"
    id: zone2_target_count
    accuracy_decimals: 0
    icon: "mdi:counter"
    unit_of_measurement: "targets"
  - platform: template
    name: "Zone3 Target Counts"
    id: zone3_target_count
    accuracy_decimals: 0
    icon: "mdi:counter"
    unit_of_measurement: "targets"
  - platform: template
    name: "Zout1 Target Counts"
    id: zone_ex1_target_count
    accuracy_decimals: 0
    icon: mdi:account-multiple-minus-outline
    unit_of_measurement: "targets"

  # Target 1
  - platform: template
    name: "Target1 X"
    id: target1_x
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    icon: mdi:focus-field-horizontal
    device_class: distance
  - platform: template
    name: "Target1 Y"
    id: target1_y
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
    icon: mdi:focus-field-vertical
  - platform: template
    name: "Target1 Speed"
    id: target1_speed
    accuracy_decimals: 2
    unit_of_measurement: 'm/s'
    state_class: measurement
    device_class: speed
  - platform: template
    name: "Target1 Resolution"
    id: target1_resolution
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
  
  # Target 2
  - platform: template
    name: "Target2 X"
    id: target2_x
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
    icon: mdi:focus-field-horizontal
  - platform: template
    name: "Target2 Y"
    id: target2_y
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
    icon: mdi:focus-field-vertical
  - platform: template
    name: "Target2 Speed"
    id: target2_speed
    accuracy_decimals: 0
    unit_of_measurement: 'm/s'
    state_class: measurement
    device_class: speed
  - platform: template
    name: "Target2 Resolution"
    id: target2_resolution
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance

  # Target 3
  - platform: template
    name: "Target3 X"
    id: target3_x
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
    icon: mdi:focus-field-horizontal
  - platform: template
    name: "Target3 Y"
    id: target3_y
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
    icon: mdi:focus-field-vertical
  - platform: template
    name: "Target3 Speed"
    id: target3_speed
    accuracy_decimals: 0
    unit_of_measurement: 'm/s'
    state_class: measurement
    device_class: speed
  - platform: template
    name: "Target3 Resolution"
    id: target3_resolution
    accuracy_decimals: 0
    unit_of_measurement: 'mm'
    state_class: measurement
    device_class: distance
  - platform: template
    name: "Target1 Angle"
    id: target1_angle
    unit_of_measurement: 'º'
    accuracy_decimals: 1
    icon: mdi:angle-acute
  - platform: template
    name: "Target2 Angle"
    id: target2_angle
    accuracy_decimals: 1
    unit_of_measurement: 'º'
    icon: mdi:angle-acute
  - platform: template
    name: "Target3 Angle"
    id: target3_angle
    accuracy_decimals: 1
    unit_of_measurement: 'º'
    icon: mdi:angle-acute

light:
  - platform: status_led
    name: sys_status
    pin: GPIO13
    internal: True
    restore_mode: ALWAYS_OFF
  - platform: binary
    name: "Red Info Light"
    output: board_info_ed
    entity_category: diagnostic
    restore_mode: ALWAYS_OFF

time:
  - platform: sntp
    id: time_now

output:
  - platform: gpio
    id: board_info_ed
    pin: GPIO12

switch:
  - platform: factory_reset
    name: Factory Reset
    disabled_by_default: True
    icon: mdi:heart-broken
    entity_category: diagnostic
  - platform: template
    name: Zout1 Enable
    id: zone_ex1_enable
    optimistic: True
    icon: mdi:account-cancel
    entity_category: config
    restore_mode: RESTORE_DEFAULT_OFF
  - platform: template
    name: Zone Enable
    id: zone_fn_enable
    optimistic: True
    icon: mdi:target-variant
    entity_category: config
    restore_mode: RESTORE_DEFAULT_ON
  - platform: template
    name: Illuminance Fast-Update
    id: bh1750_fast_update
    optimistic: True
    entity_category: diagnostic
    restore_mode: RESTORE_DEFAULT_OFF
    icon: mdi:run-fast

button:
  - platform: restart
    icon: mdi:power-cycle
    name: "ESP Reboot"
    entity_category: diagnostic

uart:
  id: uart_bus
  tx_pin: 
    number: GPIO18
    mode:
      input: true
      pullup: true
  rx_pin: 
    number: GPIO33
    mode:
      input: true
      pullup: true
  baud_rate: 256000
  parity: NONE
  stop_bits: 1
  data_bits: 8
  debug:
    direction: BOTH
    dummy_receiver: True
    after:
     delimiter: [0X55, 0XCC]
    sequence:
      - lambda: |-
          if ((millis() - id(last_update_ld2450)) <= 500) { 
            return;
          };
          id(last_update_ld2450) = millis();

          // p1
          int16_t p1_x = (uint16_t((bytes[5] << 8) | bytes[4] ));
          if ((bytes[5] & 0x80) >> 7){
            p1_x -= pow(2, 15); 
          }else{
            p1_x = 0 - p1_x;
          }

          int16_t p1_y = (uint16_t((bytes[7] << 8) | bytes[6] ));
          if ((bytes[7] & 0x80) >> 7){
            p1_y -= pow(2, 15);
          }else{
            p1_y = 0 - p1_y;
          }

          int p1_speed = (bytes[9] << 8 | bytes[8] );
          if ((bytes[9] & 0x80) >> 7){
            p1_speed -= pow(2, 15);
          }else{
            p1_speed = 0 - p1_speed;
          }
          int16_t p1_distance_resolution = (uint16_t((bytes[11] << 8) | bytes[10] )); 

          // p2
          int16_t p2_x = (uint16_t((bytes[13] << 8) | bytes[12] ));
          if ((bytes[13] & 0x80) >> 7){
            p2_x -=  pow(2, 15); 
          }else{
            p2_x = 0 - p2_x;
          }

          int16_t p2_y = (uint16_t((bytes[15] << 8) | bytes[14] ));
          if ((bytes[15] & 0x80) >> 7){
            p2_y -= pow(2, 15);
          }else{
            p2_y = 0 - p2_y;
          }

          int p2_speed = (bytes[17] << 8 | bytes[16] );
          if ((bytes[17] & 0x80) >> 7){
            p2_speed -= pow(2, 15);
          }else{
            p2_speed = 0 - p2_speed;
          }
          int16_t p2_distance_resolution = (uint16_t((bytes[19] << 8) | bytes[18] )); 

          // p3
          int16_t p3_x = (uint16_t((bytes[21] << 8) | bytes[20] ));
          if ((bytes[21] & 0x80) >> 7){
            p3_x -=  pow(2, 15); 
          }else{
            p3_x = 0 - p3_x;
          }

          int16_t p3_y = (uint16_t((bytes[23] << 8) | bytes[22] ));
          if ((bytes[23] & 0x80) >> 7){
            p3_y -= pow(2, 15);
          }else{
            p3_y = 0 - p3_y;
          }

          int p3_speed = (bytes[25] << 8 | bytes[24] );
          if ((bytes[25] & 0x80) >> 7){
            p3_speed -= pow(2, 15);
          }else{
            p3_speed = 0 - p3_speed;
          }
          
          int16_t p3_distance_resolution = (uint16_t((bytes[27] << 8) | bytes[26] )); 

          bool p1_vaild = (p1_x != 0 || p1_y > 0);
          bool p2_vaild = (p2_x != 0 || p2_y > 0);
          bool p3_vaild = (p3_x != 0 || p3_y > 0);

          // zone exlude 1

          int16_t target_count_in_zone_ex1 = 0;

          int16_t zone_ex1_x_min = id(zone_ex1_x_begin).state;
          int16_t zone_ex1_x_max = id(zone_ex1_x_end).state;
          int16_t zone_ex1_y_min = id(zone_ex1_y_begin).state;
          int16_t zone_ex1_y_max = id(zone_ex1_y_end).state;

          bool p1_zone_ex_enter = false;
          bool p2_zone_ex_enter = false;
          bool p3_zone_ex_enter = false;

          if (id(zone_ex1_enable).state){
            if (p1_vaild){
              if (p1_x >= zone_ex1_x_min && p1_x <= zone_ex1_x_max && p1_y >= zone_ex1_y_min && p1_y <= zone_ex1_y_max){
                  p1_zone_ex_enter = true;
                  target_count_in_zone_ex1 ++;
              }
            }
            if (p2_vaild){
              if (p2_x >= zone_ex1_x_min && p2_x <= zone_ex1_x_max && p2_y >= zone_ex1_y_min && p2_y <= zone_ex1_y_max){
                  p2_zone_ex_enter = true;
                  target_count_in_zone_ex1 ++;
              }
            }
            if (p3_vaild){
              if (p3_x >= zone_ex1_x_min && p3_x <= zone_ex1_x_max && p3_y >= zone_ex1_y_min && p3_y <= zone_ex1_y_max){
                  p3_zone_ex_enter = true;
                  target_count_in_zone_ex1 ++;
              }
            }
          }

          bool has_target_in_zone_ex1 = (target_count_in_zone_ex1 > 0);
          
          int16_t all_target_counts = 0;
          if (p1_vaild && !p1_zone_ex_enter){
            all_target_counts ++;
          }
          if (p2_vaild && !p2_zone_ex_enter){
            all_target_counts ++;
          }
          if (p3_vaild && !p3_zone_ex_enter){
            all_target_counts ++;
          }

          bool has_target_in_zone_all = (all_target_counts > 0);

          int16_t target_count_in_zone1 = 0;
          bool has_target_in_zone1 = false;

          int16_t target_count_in_zone2 = 0;
          bool has_target_in_zone2 = false;

          int16_t target_count_in_zone3 = 0;
          bool has_target_in_zone3 = false;

          if (id(zone_fn_enable).state){

            // zone 1 check

            int16_t zone1_x_min = id(zone1_x_begin).state;
            int16_t zone1_x_max = id(zone1_x_end).state;
            int16_t zone1_y_min = id(zone1_y_begin).state;
            int16_t zone1_y_max = id(zone1_y_end).state;

            if (p1_vaild && !p1_zone_ex_enter){
              if (p1_x >= zone1_x_min && p1_x <= zone1_x_max && p1_y >= zone1_y_min && p1_y <= zone1_y_max){
                  target_count_in_zone1 ++;
              }
            }
            if (p2_vaild && !p2_zone_ex_enter){
              if (p2_x >= zone1_x_min && p2_x <= zone1_x_max && p2_y >= zone1_y_min && p2_y <= zone1_y_max){
                  target_count_in_zone1 ++;
              }
            }
            if (p3_vaild && !p3_zone_ex_enter){
              if (p3_x >= zone1_x_min && p3_x <= zone1_x_max && p3_y >= zone1_y_min && p3_y <= zone1_y_max){
                  target_count_in_zone1 ++;
              }
            }
            has_target_in_zone1 = (target_count_in_zone1 > 0);

            // zone 2 check

            int16_t zone2_x_min = id(zone2_x_begin).state;
            int16_t zone2_x_max = id(zone2_x_end).state;
            int16_t zone2_y_min = id(zone2_y_begin).state;
            int16_t zone2_y_max = id(zone2_y_end).state;

            if (p1_vaild && !p1_zone_ex_enter){
              if (p1_x >= zone2_x_min && p1_x <= zone2_x_max && p1_y >= zone2_y_min && p1_y <= zone2_y_max){
                  target_count_in_zone2 ++;
              }
            }
            if (p2_vaild && !p2_zone_ex_enter){
              if (p2_x >= zone2_x_min && p2_x <= zone2_x_max && p2_y >= zone2_y_min && p2_y <= zone2_y_max){
                  target_count_in_zone2 ++;
              }
            }
            if (p3_vaild && !p3_zone_ex_enter){
              if (p3_x >= zone2_x_min && p3_x <= zone2_x_max && p3_y >= zone2_y_min && p3_y <= zone2_y_max){
                  target_count_in_zone2 ++;
              }
            }

            has_target_in_zone2 = (target_count_in_zone2 > 0);

            // zone 3 check

            int16_t zone3_x_min = id(zone3_x_begin).state;
            int16_t zone3_x_max = id(zone3_x_end).state;
            int16_t zone3_y_min = id(zone3_y_begin).state;
            int16_t zone3_y_max = id(zone3_y_end).state;

            if (p1_vaild && !p1_zone_ex_enter){
              if (p1_x >= zone3_x_min && p1_x <= zone3_x_max && p1_y >= zone3_y_min && p1_y <= zone3_y_max){
                  target_count_in_zone3 ++;
              }
            }
            if (p2_vaild && !p2_zone_ex_enter){
              if (p2_x >= zone3_x_min && p2_x <= zone3_x_max && p2_y >= zone3_y_min && p2_y <= zone3_y_max){
                  target_count_in_zone3 ++;
              }
            }
            if (p3_vaild && !p3_zone_ex_enter){
              if (p3_x >= zone3_x_min && p3_x <= zone3_x_max && p3_y >= zone3_y_min && p3_y <= zone3_y_max){
                  target_count_in_zone3 ++;
              }
            }
            has_target_in_zone3 = (target_count_in_zone3 > 0);

          }

          // Angle, Position and Direction, idea from walberjunior.

          float p1_angle = 0;
          if (p1_vaild){
            p1_angle = ((float)p1_x / (float)p1_y) * 180 / M_PI;;
          }

          std::basic_string<char> p1_position = "Static";
          if (p1_speed > 0) {
            p1_position = "Moving away";
          } else if (p1_speed < 0) {
            p1_position = "Approaching";
          } 

          std::basic_string<char> p1_direction = "None";
          if (p1_x > 0) {
            p1_direction = "Right";
          } else if (p1_x < 0) {
            p1_direction = "Left";
          } else if (p1_y > 0){
            p1_direction = "Middle";
          }

          float p2_angle = 0;
          if (p2_vaild){
            p2_angle = ((float)p2_x / (float)p2_y) * 180 / M_PI;;
          }

          std::basic_string<char> p2_position = "Static";;
          if (p2_speed > 0) {
            p2_position = "Moving away";
          } else if (p2_speed < 0) {
            p2_position = "Approaching";
          } 
          
          std::basic_string<char> p2_direction = "None";
          if (p2_x > 0) {
            p2_direction = "Right";
          } else if (p2_x < 0) {
            p2_direction = "Left";
          } else if (p2_y > 0){
            p2_direction = "Middle";
          }

          float p3_angle = 0;
          if (p3_vaild){
            p3_angle = ((float)p3_x / (float)p3_y) * 180 / M_PI;;
          }
          
          std::basic_string<char> p3_position = "Static";;
          if (p3_speed > 0) {
            p3_position = "Moving away";
          } else if (p3_speed < 0) {
            p3_position = "Approaching";
          } 

          std::basic_string<char> p3_direction = "None";
          if (p3_x > 0) {
            p3_direction = "Right";
          } else if (p3_x < 0) {
            p3_direction = "Left";
          } else if (p3_y > 0){
            p3_direction = "Middle";
          }

          if (id(target1_angle).state != p1_angle){
            id(target1_angle).publish_state(p1_angle);
          }
          if (id(target2_angle).state != p2_angle){
            id(target2_angle).publish_state(p2_angle);
          }
          if (id(target3_angle).state != p3_angle){
            id(target3_angle).publish_state(p3_angle);
          }

          if (p1_position != id(target1_position).state){
            id(target1_position).publish_state(p1_position);
          }
          if (p2_position != id(target2_position).state){
            id(target2_position).publish_state(p2_position);
          }
          if (p3_position != id(target3_position).state){
            id(target3_position).publish_state(p3_position);
          }

          if (p1_direction != id(target1_direction).state){
            id(target1_direction).publish_state(p1_direction);
          }
          if (p2_direction != id(target2_direction).state){
            id(target2_direction).publish_state(p2_direction);
          }
          if (p3_direction != id(target3_direction).state){
            id(target3_direction).publish_state(p3_direction);
          }

          // public all info

          if (id(target1_x).state != p1_x){
            id(target1_x).publish_state(p1_x);
          }
          if (id(target1_y).state != p1_y){
            id(target1_y).publish_state(p1_y);
          }

          float p1_m_speed = float(p1_speed) / 100.0;
          if (id(target1_speed).state != p1_m_speed){
            id(target1_speed).publish_state(p1_m_speed);
          }
          if (id(target1_resolution).state != p1_distance_resolution){
            id(target1_resolution).publish_state(p1_distance_resolution);
          }

          if (id(target2_x).state != p2_x){
            id(target2_x).publish_state(p2_x);
          }
          if (id(target2_y).state != p2_y){
            id(target2_y).publish_state(p2_y);
          }
          if (id(target2_speed).state != p2_speed){
            id(target2_speed).publish_state(p2_speed);
          }
          if (id(target2_resolution).state != p2_distance_resolution){
            id(target2_resolution).publish_state(p2_distance_resolution);
          }

          if (id(target3_x).state != p3_x){
            id(target3_x).publish_state(p3_x);
          }
          if (id(target3_y).state != p3_y){
            id(target3_y).publish_state(p3_y);
          }
          if (id(target3_speed).state != p3_speed){
            id(target3_speed).publish_state(p3_speed);
          }
          if (id(target3_resolution).state != p3_distance_resolution){
            id(target3_resolution).publish_state(p3_distance_resolution);
          }

          // publish target info
          
          if (id(all_target_count).state != all_target_counts){
            id(all_target_count).publish_state(all_target_counts);
            id(any_target_exsits).publish_state(has_target_in_zone_all);
          }else if (id(any_target_exsits).state != has_target_in_zone_all){
            id(any_target_exsits).publish_state(has_target_in_zone_all);
          }

          if (id(zone1_target_count).state != target_count_in_zone1){
            id(zone1_target_count).publish_state(target_count_in_zone1);
            id(zone1_target_exsits).publish_state(has_target_in_zone1);
          }else if (id(zone1_target_exsits).state != has_target_in_zone1){
            id(zone1_target_exsits).publish_state(has_target_in_zone1);
          }

          if (id(zone2_target_count).state != target_count_in_zone2){
            id(zone2_target_count).publish_state(target_count_in_zone2);
            id(zone2_target_exsits).publish_state(has_target_in_zone2);
          }else if (id(zone2_target_exsits).state != has_target_in_zone2){
            id(zone2_target_exsits).publish_state(has_target_in_zone2);
          }

          if (id(zone3_target_count).state != target_count_in_zone3){
            id(zone3_target_count).publish_state(target_count_in_zone3);
            id(zone3_target_exsits).publish_state(has_target_in_zone3);
          }else if (id(zone3_target_exsits).state != has_target_in_zone3){
            id(zone3_target_exsits).publish_state(has_target_in_zone3);
          }
          
          // zout
          if (id(zone_ex1_target_count).state != target_count_in_zone_ex1){
            id(zone_ex1_target_count).publish_state(target_count_in_zone_ex1);
          }

          if (id(zone_ex1_target_exsits).state != has_target_in_zone_ex1){
            id(zone_ex1_target_exsits).publish_state(has_target_in_zone_ex1);
          }

          if (!id(init_zone_publish)){
            id(init_zone_publish) = true;
          }

Concernant un code qui soit le plus fonctionnel possible j’ai trouvé ça qui m’avait l’air pas mal :
https://github.com/53l3cu5/ESP32_LD2450
Je vais le tester dans les prochains jours…

Ce qui est vraiment cool avec ce projet c’est qu’on a quelques cases à cocher concernant les paramètres pour notre détecteur comme le nombre zones de détection, le nombre de zones d’exclusion, le nom qu’on veut donner a l’entité… Ce qui facilite beaucoup le paramétrage du capteur