我们通过通道对开关进行编程。 带有OTA的esp8266(sonoff)上的MicroPython。 第一部分

大家好


在维修过程中,出现了进行通道切换的任务。 当然,我想以最简单,最方便的方式来完成此任务,并从电话中添加基本控制功能。 为此,我选择了最简单,最方便的技术(当然,我认为)-MicroPython,并开始这样做。 我在esp8266上拿了成品板,并为此分配了一个小时的空闲时间。 但是,由于它在不太受欢迎且没有试运行的项目中发生,因此任务拖了一点。


事实证明,我发现最方便的设计根本没有用。 我不得不花一些时间对此进行分析,此外,我决定对整个过程进行足够详细的描述。 文章的数量开始迅速增加,因此我决定将其分成几部分,并丢弃所有我认为不必要的细节。


第一部分包括三个部分:


  1. 选择用于开发通道开关的最简单介质的理论考虑,
  2. 在所选设备上实际启动所选基本固件,陷阱,
  3. 固件开发

选择最简单的开发环境


对于像“如果您有空闲时间的话,自己动手做”之类的智能家居,除了经典项目(例如稳定性)之外,强制性设备要求列表还增加了开发,安装和支持的便利性。 这些设备需要轻松地将必要的传感器或控制设备连接到它们。 存在与整个系统进行通信的便捷方法。 考虑到可以将设备放置在难以接触的地方,有必要确保将固件轻松写入该设备。 当然,易于开发,这对于DIY尤其重要,例如,在工作了两年后整个系统都没有故障的情况下
突然我想对固件进行一些调整。 要进行这些更正,您需要记住该系统的工作原理,有时该过程可能比调整本身花费更多的时间。


考虑一个普通的例子:您需要制作一个具有控制能力的简单直通交换机,包括从PC进行控制。 近年来,这项任务非常复杂,必须使用某种微控制器(最受欢迎的是avr或pic),并编写固件,通常,您需要阅读其文档。 如果您想开箱即用地做所有事情,则需要分开电路板,在哪里放置AC / DC,一个微控制器和一个通讯接口。 LUT(或订购印刷电路板)之后,焊接所有零件,购买编程器,然后刷新固件。 然后在2-3年后,如有必要,进行修复,查找所有设备并从头开始学习所有内容...


为了简化此过程,现成的解决方案开始出现在市场上。 最成功的解决方案是Arduino。 该解决方案由具有更新功能的引导加载程序IDE提供,它使您可以通过标准接口专门使用设备,而无需使用程序员。 这样就可以制作固件,仅具有
对那里的一切安排非常肤浅。 一组外部模块可以在不使用烙铁的情况下连接设备。 但是无论如何,要进行编辑,您需要安装Arduino软件,并将固件存储在某个地方。


我们的直通开关将变得足够大,它将包含一个Arduino板+ AC / DC +继电器模块。 而且,如果需要进行调整,您将不得不痛苦地记住代码所在的位置,然后再次安装Arduino软件。


为了省去编译源代码的需要(即安装其他软件并存储它),最合乎逻辑的解决方案似乎是使用解释器或直接在微控制器本身上编译代码。 幸运的是,现在已经出现了可以做到这一点的项目。 例如,esp8266微控制器的lua语言解释器NodeMCU:固件本身具有对文件系统的内置支持,可让您从设备加载脚本/从设备读取脚本。 另一个相当严肃的项目是Micropython,这是专门为微控制器量身定制的python简化版本。 将进行讨论。


MicroPython是当今最流行的python编程语言之一的实现。 它支持多种架构和SoC(裸臂,CC3200,esp8266,esp32,nRF,pic16bit,stm32)。 该项目正在积极开发中,并具有大量附加模块。


esp8266微处理器非常适合用作硬件部件,因为基于其构建的廉价wifi开关模块已在市场上出售。 它们包含了我们所需的一切:AC / DC,具有内置通信接口(wifi)的微控制器。 以Sonoff品牌出售。 esp8266微处理器不包含内存,它是单独焊接的,并且可以具有不同的大小。 对于Sonoff Basic,他们放置了1Mb模块。


在esp8266上启动基本固件。 Sonoff基本版。


在没有陷阱的情况下,可以立即进行python编程。 但是,不幸的是,有许多问题需要解决,为了编程和修改固件,这是非常容易和简单的。 当然,我们有兴趣通过wifi进行此操作,而不使用笔记本电脑以外的任何其他设备。


当然,第一个陷阱是主板上记录的基本固件。 如果购买了调试板,则很可能会在其上找到NodeMCU(如果是Sonoff Basic,则是专有固件)。 为了自己准备该板,您需要在此处写下必要的固件。 在某些微控制器中,有必要购买
一个特殊的程序员,对于我们来说很幸运,您只需要一个USB <-> UART转换器即可。 如果使用微控制器,它将不止一次派上用场,它们的价格通常在3美元左右。


Sonoff Basic没有可用的梳子允许您通过UART进行连接,我们需要用它来对器件进行编程。 为了简单地对设备进行编程,没有必要将烙铁拿在手中,它足以使触点倾斜并记下固件。 考虑到进一步的工作将通过wifi进行,我们将不再需要这些联系人。 但是我们通过通道实现了转换,这意味着我们需要焊接,
至少三条腿。


对于Sonoff Basic,只有1个免费的GPIO连接器和2个RX,TX连接器。 考虑到我们需要自己进行一次RX,TX(以刷新固件),将来可以将它们重新编程为GPIO,这要归功于esp8266。 但是在这种情况下,我们需要放弃通过UART进行调试,幸运的是我们已经计划这样做,因为从方便的角度来看,通过wifi进行调试要简单得多。


由于MicroPython的版本可能会在此过程中更改,因此我们有兴趣通过wifi调试更新方法。 OTA来了。 OTA是允许您对设备进行重新编程的固件。 它的工作非常简单。 打开设备电源后,固件会确定是否需要对其进行重新编程,如有必要,将启动特殊功能。
wifi updater(如果没有)将启动用户固件。 实现可能有所不同,固件可能会覆盖自身或写入内存的空闲区域。 您还可以确定是否以完全不同的方式运行配音程序。 例如,考虑自定义固件的收敛性,如果它不收敛,
然后强行去闪烁。 您可以从GPIO读取数据或在其他地方编写有关需要开始更新的信息。


作为更新程序,MicroPython项目指的是yaota8266项目。 Yaota8266声称正在刷新设备并签名每个数据包。 应该注意的是,公钥是嵌入在固件本身中的,这就是为什么上传已经组装好的固件没有意义的原因,因为有必要在此处缝制密钥。
没有功能可以修改组合图像中的私钥,因此在我们这种情况下,您可以更轻松地自行组装固件。 一个有趣的功能是签名验证功能是但在代码中被注释掉了,即 实际上,我们在没有任何安全收益的情况下遇到了困难。 yaota8266的基本版本不可用,
幸运的是,在github上有很多叉子可以解决这个问题,此外,它们还具有基于写入RTC区域来确定是否应执行刷新的功能,这使得将MicroPython切换到引导加载程序模式成为可能。


即使包括所有的更正,我们的OTA固件也会写入错误,但是可以在NodeMCU调试板上成功运行。 这是由于超时。 从主机更新时,将发送UDP数据包,并且如果闪存中的记录花费的时间比平时长,则会发生响应,并发生超时,然后再次发送数据包。 好处很容易解决,
只是增加ota-client代码中的超时。


Sonoff上的OTA + MicroPython捆绑包也有一些奇怪的地方。 其中之一与以下事实有关:在esp-sdk中使用SPI Flash的标准功能在4k块上运行,并且选择该块大小来实现FAT文件系统。 反过来,由于SPI Flash仅为1Mb,其中〜300Kb是OTA固件,〜500Kb是MicroPython固件,因此文件系统的剩余空间不足200Kb,即 少于50个方块。 但是,选择的实现fatfs的库无法创建少于50个块的FS。有几种方法可以解决此问题:减小块大小(FAT允许您设置512),修复FatFs库,使用SPI FS(希望没有这种怪异)。 我采取了将块减少到512的方法。


微控制器使用SPI闪存-这是NOR和/或NAND存储器。 该存储器的显着之处在于没有“写入任何数据”的概念。 您只能重置该值(为0xff),或将所需的位设置为“ 0”。 SPI Flash通常是NOR存储器,它具有将任何字节重置为0xff的功能,而NAND仅可以按块重置。 即 如果复位块的最小大小是4k,为了写
1字节的存储器,必须读取整个块,将其重置为0xFF,然后通过将所需的字节设置为所需的值来写入该块。 SPI Flash的制造商具有大致相同的API集,但是,正如实践所示,写入SPI Flash的一个字节的命令可能有所不同。 在写入0xFF之前,它将自动重置的某个位置,而不是在某个位置。


如果将FAT部分更改为512字节,如果特定的SPI闪存在记录时不支持自动字节重置,则可能会导致系统损坏。 我在Sonoff Basic中遇到了这种记忆。 有传言说他们曾经在那儿安装Winbond 25q80bv,但现在安装的是PUYA 25q80h,它的最小清理块为256字节。 解决方案似乎
很简单,您只需要在写入FAT块之前擦除将要写入的两个页面,但是由于sdk-esp仅支持删除4k块,因此实现起来很复杂。 由于写入FAT对于我们的切换非常少见,
仅当更新固件脚本时,您才可以采用错误的方式,以4k块更新512字节块。 该存储器的文档说该存储器可以承受100,000个重写周期。 对问题的类似规避将使我们将此值减少4倍,即 高达25,000。


MicroPython默认情况下具有一个控制台,称为REPL并通过COM端口工作。 我们对这种状况不太满意,因为我们想通过wifi与设备进行通信。 幸运的是,在MicroPython中,WebRepl也成为标准配置,但是它不会自动启动。 您可以在boot.py中注册自动运行,但是我决定直接从系统文件_boot.py中运行它,它被缝入固件文件本身。


首次启动后,我们的固件将创建一个文件系统,启动webrepl并创建一个访问点。 您可以连接到它并规定用于连接到本地网络的参数,或者像我一样,使用com端口配置网络,此后仅应使用wifi。


为了进行试用,您可以使用以javascript编写的webrepl客户端。 可以在项目相应页面上的浏览器中启动客户端。 另一个选择是使用mpfshell项目,它为使用设备提供了更方便的功能。


因此,在克服了所有这些陷阱之后,您可以直接对交换机进行编程。


固件开发


要开发固件,我们需要对GPIO的工作原理有一个大概的了解。 通常,这可以完全凭直觉来理解:


  1. 如果我们设置输出模式(OUT),则该支路产生GND或Vcc。
  2. 如果我们设置输入模式(IN),则支路“悬空”,在这种情况下,微控制器可以发出任何东西
  3. 为了使微控制器不发出任何东西,可以使用内置微控制器将支脚拉至所需值
    上拉电阻PULL_UP或PULL_DOWN。

您还需要了解什么是中断:在我们的案例中,这是发生某种事件时需要执行的代码:按下/释放按钮或从本地网络收到一条消息,表明应该关闭/打开设备。


首先,让我们用Python编写一个简单的切换(非传递)程序。


from machine import Pin class SW: def __init__(self, portin, portout): self.pin = Pin(portin , Pin.PULL_UP) #  self.pout = Pin(portout, Pin.OUT) #  #  self._auto(),       self.pin.irq(trigger=Pin.IRQ_RISING|Pin.IRQ_FALLING, handler=self._auto) self.value = 0 def _auto(self, _=0): if self.value: res = self.pin.value() else: res = not self.pin.value() self.pout.value(res) def change(self, val=2): """   0, ,  1, ,  2  """ if val == 2: self.value = not self.value else: self.value = val self._auto() sw = SW(14, 12) 

我命名了这个switch.py​​文件,并命令它在boot.py中运行:


 from switch import sw 

启动固件后,我得到了一个sw对象,如果执行sw.change(),将发生程序切换
切换到另一个位置。 当空闲引脚与微控制器中的Vcc短路时
继电器分别打开或关闭。


下一步将是启动MQTT客户端以及从电话切换开关的功能。

Source: https://habr.com/ru/post/zh-CN438624/


All Articles