懒人创建智能家居之二——智能控制节点创建和连接


1 概述
      在完成基本Home Assistant 操作系统并创建路由服务器之后,就可以添加智能控制节点了。在这个Home Assistant 操作系统的控制面板中,已经有很多定制的工具了。这里需要添加并使用ESPhome插件ESPHome,这样才能够添加所述定制的开发板和节点,这里使用的是ESP32C3和Rasperberry Pico W。并同时连接温度湿度传感器ADH20和照度传感器,以及控制LED照度。
IMG_20231225_210605.jpg
2 所需硬件
2.1 ESP32C3模块
2.2 Rasperberry Pico W
2.3 温度湿度传感器ADH20和照度传感器,以及LED。

3 开始搞一下
3.1 首先进入控制台的ESPHome,可以见到已经创建的节点ESP32C3
HA_17.PNG
点击edit进入yaml编辑界面
HA_18.PNG
这个界面是一个文本编辑器,描述了这个节点是在ESPhome插件下的,使用arduino创建并下载代码的esp32开发板,并且定义了无线连接的ssid接入点和密码,便于无线连接
  1. esphome:
  2.   name: xiao-esp32c3
  3.   platformio_options:
  4.    board_build.flash_mode: dio

  5. esp32:
  6.   board: seeed_xiao_esp32c3
  7.   variant: esp32c3
  8.   framework:
  9.     type: arduino
  10.     platform_version: 5.4.0

  11. logger:
  12. hardware_uart: UART0

  13. api:

  14. ota:

  15. wifi:
  16.   ssid: "UMASS fried chicken"
  17.   password: "Zacharyloveschicken"

  18.   # Enable fallback hotspot (captive portal) in case wifi connection fails
  19.   ap:
  20.     ssid: "Xiao-Esp32C3 Fallback Hotspot"
  21.     password: "MoLTqZUvHwWI"
3.2 开始安装
然后点击INSTALL安装,确实,就是在这里,用这个文本就算完成编程了。随后立刻跳出了这个硬件的选择,可以看出都是ESP系列的各种模块,以及PICO W.
HA_20.PNG
接着把开发板模块连接在树莓派上,选择设备,就跳出了连接的串口,
HA_21.PNG
选择这个串口,就开始如下显示,编译安装了。具体其中的魔法,在后面详述。
HA_22.PNG
同时这里还提供了另一种安装方式,就是通过网页安装用esphome网页GUI,进入这个选项,这个是在后台自己独自跑圈,形成可下载的bin文件,
HA_23.PNG
然后进入如下esphome gui直接上传并安装到连接到串口的开发板
HA_25.PNG
下载安装成功后继续撒花。
HA_26.PNG
这个过程其实还有另一个用处,就是用命令行创建并生成独立的bin文件,自行下载。
具体的这个操作所执行的过程就如下
HA_24.PNG
如果一切顺利,就可以继续启动这个节点的运行,随后继续在这个页面显示log的过程。
HA_27.PNG
这样这个节点就创建成功并成功运行了。现在可以安全关闭这个页面,进入原先的页面,看起来没没啥变换啊。
HA_30.PNG
貌似没变化,但是注意这个右上角的字符已经显示时online了,这个节点已经被识别并上线了。
3.3 添加节点到控制台面板
回到主页,就可以看到已经发现了新的esphome节点的esp32
HA_31.PNG
添加配置这个已经发现的设备
HA_32.PNG
选择安装的位置,是在哪个房间
HA_36.PNG
确认后,就可以成功添加到控制面板。
HA_33.PNG
3.4 添加传感器节点
    这个节点添加后,就需要安装对于传感器的采集,对于风机,照明等的控制。按照前面的连接方法连接传感器并修改前面提到的yaml文件,添加下述i2c和adc定义
  1. captive_portal:

  2. i2c:
  3.   sda: GPIO6
  4.   scl: GPIO7
  5.   scan: True
  6.   id: bus_0x38

  7. sensor:
  8.   - platform: aht10
  9.     temperature:
  10.       name: "Living Room Temperature"
  11.     humidity:
  12.       name: "Living Room Humidity"
  13.     update_interval: 60s

  14.   - platform: adc
  15.     pin: GPIO2
  16.     name: "Light Sensor"
  17.     update_interval: 6s   
上面的定义了节点的性质和位置,其中对于引脚的访问。重复上面的过程,再次编译并安装
HA_34.PNG
成功下载
HA_35.PNG
随后按照功能加节点的传感器读数
IMG_20231225_210515.jpg
这里找到了照度传感器的读数,现在显示0.61V,这个添加到控制面板的控制台如下,这时是在暗处,只有0.08V,每隔6秒采样一下。
IMG_20231225_210533.jpg
4 面向文本的低代码开发解密
4.1 采用pico w为例,先如前述在esphome中添加设备,并安装下载yaml
PICOW-01.PNG
这样就在esphome中注册成功了
4.2 其实,上述的过程就是一个创建工程并安装的过程。那么具体可以在计算机的命令行来实现
首先使用
pip install esphome

来安装开发工具,随后补充安装缺失的插件,这里platformio因为版本不兼容,需要卸载原有包并新安装
PICOW-02.PNG
然后选择
esphome picow.yaml compile
执行编译,成功后如下
PICOW-03.PNG
编译成功的是一个uf2格式的文件
PICOW-04.PNG
成功以后把这个文件安装到pico w就可以自行启动了。不用再重复上面的过程。并且同样可以添加接点,设计功能。
4.3 解密时间
     这个HomeAssistant操作系统中esphome的使用方法,是首先把yaml文件转换成了一个arduino程序。
  1. // Auto generated code by esphome
  2. // ========== AUTO GENERATED INCLUDE BLOCK BEGIN ===========
  3. #include "esphome.h"
  4. using namespace esphome;
  5. using std::isnan;
  6. using std::min;
  7. using std::max;
  8. using namespace light;
  9. wifi::WiFiComponent *wifi_wificomponent;
  10. mdns::MDNSComponent *mdns_mdnscomponent;
  11. StartupTrigger *startuptrigger;
  12. Automation<> *automation;
  13. using namespace output;
  14. gpio::GPIOBinaryOutput *LED;
  15. rp2040::RP2040GPIOPin *rp2040_rp2040gpiopin;
  16. rp2040_pwm::RP2040PWM *led;
  17. rp2040::RP2040GPIOPin *rp2040_rp2040gpiopin_2;
  18. interval::IntervalTrigger *interval_intervaltrigger;
  19. Automation<> *automation_2;
  20. output::TurnOnAction<> *output_turnonaction;
  21. DelayAction<> *delayaction;
  22. output::TurnOffAction<> *output_turnoffaction;
  23. monochromatic::MonochromaticLightOutput *monochromatic_monochromaticlightoutput;
  24. light::LightState *pulsating_led;
  25. light::PulseLightEffect *light_pulselighteffect;
  26. light::LightControlAction<> *light_lightcontrolaction;
  27. #define yield() esphome::yield()
  28. #define millis() esphome::millis()
  29. #define micros() esphome::micros()
  30. #define delay(x) esphome::delay(x)
  31. #define delayMicroseconds(x) esphome::delayMicroseconds(x)
  32. // ========== AUTO GENERATED INCLUDE BLOCK END ==========="

  33. void setup() {
  34.   // ========== AUTO GENERATED CODE BEGIN ===========
  35.   // rp2040:
  36.   //   board: rpipicow
  37.   //   framework:
  38.   //     platform_version: https:github.com/maxgerhardt/platform-raspberrypi.git
  39.   rp2040::setup_preferences();
  40.   // esphome:
  41.   //   name: rpi-pico
  42.   //   friendly_name: Raspberry Pi Pico W
  43.   //   on_boot:
  44.   //   - then:
  45.   //     - light.turn_on:
  46.   //         id: pulsating_led
  47.   //         effect: Slow pulse
  48.   //         state: true
  49.   //       type_id: light_lightcontrolaction
  50.   //     automation_id: automation
  51.   //     trigger_id: startuptrigger
  52.   //     priority: 600.0
  53.   //   build_path: build/rpi-pico
  54.   //   area: ''
  55.   //   platformio_options: {}
  56.   //   includes: []
  57.   //   libraries: []
  58.   //   name_add_mac_suffix: false
  59.   //   min_version: 2023.12.3
  60.   App.pre_setup("rpi-pico", "Raspberry Pi Pico W", "", "", __DATE__ ", " __TIME__, false);
  61.   // light:
  62.   // wifi:
  63.   //   ap:

  64.   wifi_wificomponent = new wifi::WiFiComponent();
  65.   wifi_wificomponent->set_use_address("rpi-pico.local");
  66.   {
  67.   wifi::WiFiAP wifi_wifiap_2 = wifi::WiFiAP();
  68.   wifi_wifiap_2.set_ssid("TP-LINK_2.4GHz_FFF1EC");
  69.   wifi_wifiap_2.set_password("13810963660");
  70.   wifi_wifiap_2.set_priority(0.0f);
  71.   wifi_wificomponent->add_sta(wifi_wifiap_2);
  72.   }
  73.   {
  74.   wifi::WiFiAP wifi_wifiap = wifi::WiFiAP();
  75.   wifi_wifiap.set_ssid("PICOW Fallback Hotspot");
  76.   wifi_wifiap.set_password("Checwifi0617");
  77.   wifi_wificomponent->set_ap(wifi_wifiap);
  78.   }
  79.   wifi_wificomponent->set_ap_timeout(60000);
  80.   wifi_wificomponent->set_reboot_timeout(900000);
  81.   wifi_wificomponent->set_power_save_mode(wifi::WIFI_POWER_SAVE_LIGHT);
  82.   wifi_wificomponent->set_fast_connect(false);
  83.   wifi_wificomponent->set_passive_scan(false);
  84.   wifi_wificomponent->set_enable_on_boot(true);
  85.   wifi_wificomponent->set_component_source("wifi");
  86.   App.register_component(wifi_wificomponent);
  87.   // mdns:
  88.   //   id: mdns_mdnscomponent
  89.   //   disabled: false
  90.   //   services: []
  91.   mdns_mdnscomponent = new mdns::MDNSComponent();
  92.   mdns_mdnscomponent->set_component_source("mdns");
  93.   App.register_component(mdns_mdnscomponent);
  94.   startuptrigger = new StartupTrigger(600.0f);
  95.   startuptrigger->set_component_source("esphome.coroutine");
  96.   App.register_component(startuptrigger);
  97.   automation = new Automation<>(startuptrigger);
  98.   // output:
  99.   // output.gpio:
  100.   //   platform: gpio
  101.   //   pin:
  102.   //     number: 25
  103.   //     mode:
  104.   //       output: true
  105.   //       input: false
  106.   //       open_drain: false
  107.   //       pullup: false
  108.   //       pulldown: false
  109.   //       analog: false
  110.   //     id: rp2040_rp2040gpiopin
  111.   //     inverted: false
  112.   //   id: LED
  113.   LED = new gpio::GPIOBinaryOutput();
  114.   LED->set_component_source("gpio.output");
  115.   App.register_component(LED);
  116.   rp2040_rp2040gpiopin = new rp2040::RP2040GPIOPin();
  117.   rp2040_rp2040gpiopin->set_pin(25);
  118.   rp2040_rp2040gpiopin->set_inverted(false);
  119.   rp2040_rp2040gpiopin->set_flags(gpio::Flags::FLAG_OUTPUT);
  120.   LED->set_pin(rp2040_rp2040gpiopin);
  121.   // output.rp2040_pwm:
  122.   //   platform: rp2040_pwm
  123.   //   pin:
  124.   //     number: 15
  125.   //     mode:
  126.   //       output: true
  127.   //       input: false
  128.   //       open_drain: false
  129.   //       pullup: false
  130.   //       pulldown: false
  131.   //       analog: false
  132.   //     id: rp2040_rp2040gpiopin_2
  133.   //     inverted: false
  134.   //   id: led
  135.   //   zero_means_zero: false
  136.   //   frequency: 1000.0
  137.   led = new rp2040_pwm::RP2040PWM();
  138.   led->set_component_source("rp2040_pwm.output");
  139.   App.register_component(led);
  140.   led->set_zero_means_zero(false);
  141.   rp2040_rp2040gpiopin_2 = new rp2040::RP2040GPIOPin();
  142.   rp2040_rp2040gpiopin_2->set_pin(15);
  143.   rp2040_rp2040gpiopin_2->set_inverted(false);
  144.   rp2040_rp2040gpiopin_2->set_flags(gpio::Flags::FLAG_OUTPUT);
  145.   led->set_pin(rp2040_rp2040gpiopin_2);
  146.   led->set_frequency(1000.0f);
  147.   // interval:
  148.   //   - interval: 500ms
  149.   //     then:
  150.   //     - output.turn_on:
  151.   //         id: LED
  152.   //       type_id: output_turnonaction
  153.   //     - delay: 250ms
  154.   //       type_id: delayaction
  155.   //     - output.turn_off:
  156.   //         id: LED
  157.   //       type_id: output_turnoffaction
  158.   //     trigger_id: trigger
  159.   //     automation_id: automation_2
  160.   //     id: interval_intervaltrigger
  161.   //     startup_delay: 0s
  162.   interval_intervaltrigger = new interval::IntervalTrigger();
  163.   interval_intervaltrigger->set_component_source("interval");
  164.   App.register_component(interval_intervaltrigger);
  165.   automation_2 = new Automation<>(interval_intervaltrigger);
  166.   output_turnonaction = new output::TurnOnAction<>(LED);
  167.   delayaction = new DelayAction<>();
  168.   delayaction->set_component_source("interval");
  169.   App.register_component(delayaction);
  170.   delayaction->set_delay(250);
  171.   output_turnoffaction = new output::TurnOffAction<>(LED);
  172.   automation_2->add_actions({output_turnonaction, delayaction, output_turnoffaction});
  173.   interval_intervaltrigger->set_update_interval(500);
  174.   interval_intervaltrigger->set_startup_delay(0);
  175.   // light.monochromatic:
  176.   //   platform: monochromatic
  177.   //   output: led
  178.   //   id: pulsating_led
  179.   //   effects:
  180.   //   - pulse:
  181.   //       name: Slow pulse
  182.   //       transition_length: 2s
  183.   //       update_interval: 2s
  184.   //       min_brightness: 0.0
  185.   //       max_brightness: 1.0
  186.   //     type_id: light_pulselighteffect
  187.   //   disabled_by_default: false
  188.   //   restore_mode: ALWAYS_OFF
  189.   //   gamma_correct: 2.8
  190.   //   default_transition_length: 1s
  191.   //   flash_transition_length: 0s
  192.   //   output_id: monochromatic_monochromaticlightoutput
  193.   //   name: pulsating_led
  194.   //   internal: true
  195.   monochromatic_monochromaticlightoutput = new monochromatic::MonochromaticLightOutput();
  196.   pulsating_led = new light::LightState(monochromatic_monochromaticlightoutput);
  197.   App.register_light(pulsating_led);
  198.   pulsating_led->set_component_source("light");
  199.   App.register_component(pulsating_led);
  200.   pulsating_led->set_name("pulsating_led");
  201.   pulsating_led->set_object_id("pulsating_led");
  202.   pulsating_led->set_disabled_by_default(false);
  203.   pulsating_led->set_internal(true);
  204.   pulsating_led->set_restore_mode(light::LIGHT_ALWAYS_OFF);
  205.   pulsating_led->set_default_transition_length(1000);
  206.   pulsating_led->set_flash_transition_length(0);
  207.   pulsating_led->set_gamma_correct(2.8f);
  208.   light_pulselighteffect = new light::PulseLightEffect("Slow pulse");
  209.   light_pulselighteffect->set_transition_on_length(2000);
  210.   light_pulselighteffect->set_transition_off_length(2000);
  211.   light_pulselighteffect->set_update_interval(2000);
  212.   light_pulselighteffect->set_min_max_brightness(0.0f, 1.0f);
  213.   pulsating_led->add_effects({light_pulselighteffect});
  214.   monochromatic_monochromaticlightoutput->set_output(led);
  215.   // network:
  216.   //   enable_ipv6: false
  217.   light_lightcontrolaction = new light::LightControlAction<>(pulsating_led);
  218.   light_lightcontrolaction->set_state(true);
  219.   light_lightcontrolaction->set_effect("Slow pulse");
  220.   automation->add_actions({light_lightcontrolaction});
  221.   // =========== AUTO GENERATED CODE END ============
  222.   App.setup();
  223. }

  224. void loop() {
  225.   App.loop();
  226. }
仔细研究,虽然代码长,但仍然是包括初始化部分
setup()
以及
  1. void loop() {
  2.   App.loop();
  3. }
这样的标准循环过程。第一行导入的头文件
  1. #include "esphome.h"
就一步把代码带入了esphome的开发环境,后面的编译完全借用了arduino的开发工具,整个这个都是开源代码,提供开发者更多的选择空间。并且具备工业化生产的条件,因为ESP32是一个开发者的大众情人,因为性价比好广泛采用,这样的玩法,可以让独立开发者直接接入home assistant的开发生态,提供良好的接入和访问环境。