We program the switch through passage. MicroPython on esp8266 (sonoff) with OTA. Part 1

Hello.


In the process of repair, the task arose of making a through switch. Of course, I wanted to make it the easiest and most convenient way by adding basic management functions from the phone. I chose the most simple and convenient technology for this (of course, in my opinion) - MicroPython, and started doing it. I took a ready fee for esp8266 and set aside an hour of free time for this. But, as it happens with not very popular and not run-in projects, the task was a bit delayed.


As it turned out, the design that I thought was the most convenient, it turns out, does not work at all. I had to spend some time analyzing this, in addition, I decided to describe the whole process in detail. The volume of the article began to grow rapidly, so I decided to divide it into parts and throw away all the unnecessary details in my opinion.


The first part consists of three parts:


  1. Theoretical reasoning on the choice of the most simple environment for the development of a through switch,
  2. Practical launch of the selected base firmware on the selected equipment, pitfalls,
  3. Firmware development

Choosing the most simple development environment


For a smart home like "do it yourself, if you have a minute of free time", the list with mandatory equipment requirements, in addition to classic items (for example, stability), adds ease of development, installation and support. Devices are required so that the necessary sensors or control devices can be easily connected to them. That there were convenient and easy ways to communicate with the entire system. It is necessary to ensure the ease of writing firmware to this device, given that the device can be located where it will be quite difficult to get to it. And of course the ease of development, it is especially critical for a homemade product, when, for example, 2 years after work without the failure of the entire system
suddenly I want to add some corrections to the firmware. To make these corrections, you need to remember how this system works, which sometimes can take longer than the adjustment itself.


Consider a banal example: you need to make a simple pass switch with the ability to control it, including from a PC. In recent times, this task was quite complicated, it was necessary to take some kind of microcontroller (the most popular were avr or pic), and to write the firmware, as a rule, you need to read the documentation on it. If you want to do everything "out of the box", you need to dilute the board, where to put the AC / DC, microcontroller and communication interface. After LUT-a (or ordering printed circuit boards) to solder everything, buy a programmer, sew the firmware. And then after 2-3 years, if necessary, to fix something, look for all the equipment and study everything from scratch ...


To simplify this process, ready-made solutions began to appear on the market. The most successful solution is Arduino. This solution gives the IDE, a bootloader with the update function, which allows you to work with the device exclusively through a standard interface without using programmers. It allows you to make firmware, having only a
very superficial understanding of how everything is arranged there. A set of external modules allows you to connect devices without a soldering iron. But still, to make edits, you need to install the Arduino software, store somewhere firmware.


Our pass-through switch will be large enough to contain the Arduino board + AC / DC + relay module. And if you need to make adjustments, you will have to painfully remember where the code lies and install the Arduino software again.


In order to save yourself from having to compile the source code (ie, install additional software and store it), the most logical solution seems to be either using interpreters, or directly compiling the code on the microcontroller itself. Fortunately, at the moment there are projects that allow you to do this. For example, NodeMCU, the lua language interpreter under the esp8266 microcontroller: the firmware itself has support for the file system, which allows downloading / reading scripts to / from the device. Another fairly serious project is Micropython, this is a truncated version of python, which is specially tuned for microcontrollers. About him and will be discussed.


MicroPython is the implementation of one of the most popular programming language now python. Supports a large number of architectures and SoC (bare-arm, CC3200, esp8266, esp32, nRF, pic16bit, stm32). The project is actively developing and has a large number of additional modules.


The esp8266 microprocessor is very well suited for hardware, due to the fact that the market sells low-cost wifi switch modules built just on it. They contain everything we need: AC / DC, a microcontroller with a built-in communication interface (wifi). Available under the brand name Sonoff. Microprocessors esp8266 does not contain memory, it is soldered separately and may have a different size. For Sonoff Basic put 1Mb modules.


Run the basic firmware on esp8266. Sonoff Basic.


In the absence of pitfalls, it would be possible to proceed directly to programming in python. But, unfortunately, there are a number of issues that need to be addressed in order to program and modify the firmware was very easy and simple. Of course, we are interested in doing this by wifi, without using any additional devices other than a laptop.


The first pitfall, of course, is the base firmware, which is recorded on your board. If you bought a debug board, you will most likely find NodeMCU on it, if Sonoff Basic, then proprietary firmware. To prepare this board for yourself, you need to write the necessary firmware there. In some microcontrollers for this you need to purchase a
special programmer, in our case we are lucky, you just need to get a USB <-> UART converter. If you work with microcontrollers, it will come in handy for you more than once, and their price is usually in the range of $ 3.


There is no comb for Sonoff Basic that allows you to connect via UART, and we need this to program the device. In order to simply program the device, it is not necessary to take the soldering iron in hand, just lean the contacts and write the firmware. Taking into account that further work will be via wifi, we will no longer need these contacts. But we are implementing a pass-through switch, which means we need
at least three soldered legs.


For Sonoff Basic there is only 1 free GPIO connector, and 2 RX, TX connectors. Taking into account that we need RX, TX ourselves once (to sew the firmware), in the future they can be reprogrammed to GPIO, since esp8266 allows us to do this. But in this case, we need to abandon debugging via UART, fortunately we already planned to do this, since it is much easier to debug via wifi, in terms of convenience.


Since the version of MicroPython in the process may vary, we are interested in debugging the update method via wifi. OTA comes to the rescue. OTA is a firmware that allows you to reprogram the device. It works quite simply. After turning on the device, the firmware determines whether it needs to be reprogrammed, if necessary, launches a special
wifi update program, if not, launches the user firmware. The implementation can be different, the firmware can overwrite itself or write to a free area of ​​memory. It is also possible to determine whether it is necessary to start the rewriting program at all. For example, consider the cheksumma custom firmware, if it does not converge,
then forcibly go to the flashing. You can read data from the GPIO or record information about the need to run the update somewhere else.


As an update program, the MicroPython project refers to the yaota8266 project. Yaota8266 claims to be flashing the device and signing each package. It should be noted that the public key is embedded in the firmware itself, which is why it makes no sense to upload the already assembled firmware, since it is necessary to sew up your key there.
There is no function of modifying the private key in the assembled image, so in our case it is easier to assemble the firmware yourself. An interesting feature is that there is a signature verification function, but it is commented out in the code, i.e. in fact, we get difficulties without any safety gains. The basic version of yaota8266 is not going,
blessing on github, there are forks that solve this problem plus add the ability to determine whether to do a flashing based on an entry in the RTC area, which makes it possible to switch MicroPython to bootloader mode.


Even after enabling all the fixes, our firmware with OTA will record with errors, but will work successfully on NodeMCU debug boards. This is due to timeouts. When updating from the host machine, UDP packets are sent and a response is expected, if writing to the flash takes longer than usual, timeout occurs, and the packet is forwarded again. The benefit is easy to fix,
simply by increasing the timeouts in the code ota-client.


OTA + MicroPython on Sonoff also has some interesting oddities. One of them is related to the fact that the full-time functions of working with SPI Flash in esp-sdk operate on 4k blocks, and this block size was chosen to implement the FAT file system. In turn, due to the fact that SPI Flash is only 1Mb, of which ~ 300Kb is OTA firmware, ~ 500Kb is MicroPython firmware, less than 200Kb remains for the file system, i.e. less than 50 blocks. However, the selected library that implements fatfs cannot create a file system with less than 50 blocks. You can solve the problem in different ways: you can reduce the block size (FAT allows you to set 512), fix the FatFs library, use SPI FS (hoping that there are no such oddities). I took the path of reducing the block to 512.


Microcontrollers use SPI Flash - this is NOR and / or NAND memory. The remarkable thing about this memory is that there is no such thing as “write any data”. You can only reset the value (to 0xff), or set the desired bits to "0". SPI Flash is usually NOR memory, it has the function of resetting any byte to 0xff, while NAND can only reset blocks. Those. if the minimum block size is 4k, in order to write
1 byte of memory, you need to read the whole block, reset it to 0xFF, and then write the block, setting the desired byte to the desired value. The manufacturers of SPI Flash have approximately the same set of APIs for work, but, as practice has shown, the command for writing one byte of SPI Flash may differ. Somewhere it will automatically reset before writing to 0xFF, somewhere not.


If the FAT partition is changed to 512 bytes, there is a chance to get a battered system if a particular SPI Flash does not support automatic reset of the byte during recording. And this is exactly the kind of memory I got into Sonoff Basic. Rumor has it that earlier Winbond 25q80bv was installed there, but now PUYA 25q80h, which has a minimum cleaning block of 256 bytes. The solution is seemingly
simple, you just need to erase two pages before writing the FAT block, where it will be written to, but the implementation is complicated by the fact that sdk-esp only supports deletion in 4k blocks. Since the FAT will rarely write to our switch,
Only when updating the firmware scripts, you can go the wrong way and update the block 512 bytes in 4k blocks. The documentation for this memory states that the memory can withstand 100,000 rewriting cycles, i.e. such a workaround will reduce this value to us by 4 times, i.e. up to 25,000.


In MicroPython, by default there is a console, it is called REPL and works through the COM port. We are not very happy with this situation, as we want to communicate with the device via wifi. Fortunately, WebRepl is also running well in MicroPython, but it does not start automatically. You can set the autorun in boot.py, but I decided to run directly from _boot.py, the system file, it is sewn into the firmware file itself.


After the first launch, our firmware will create a file system, launch webrepl and create an access point. You can connect to it and set the parameters for connecting to your local network, or, as I did, configure the network using the com port, and then use only wifi.


For familiarization work, you can use webrepl client written in javascript. The client can be launched in the browser on the corresponding page of the project. Another option is to use the mpfshell project, it gives more convenient functions for working with the device.


So, after overcoming all these pitfalls, you can go directly to the switch programming.


Firmware development


To develop the firmware, we need to have a rough idea of ​​how GPIO works. In general, this can be understood purely intuitively:


  1. If we set the output mode (OUT), then the foot gives out either GND or Vcc.
  2. If we set the input mode (IN), then the leg "dangles in the air", in this case, the microcontroller can give anything
  3. To prevent the microcontroller from delivering anything, the foot can be pulled up to the desired value using the
    pull-up resistors PULL_UP or PULL_DOWN built into the microcontroller .

You also need to have an idea of ​​what interrupts are: in our case, this is the code that needs to be executed if an event occurs: a button was pressed / released or a message came from the local network that the device should be turned off / on.


To begin with we will write the program of the simple switch (but not pass) on 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)  

I called this file switch.py ​​and registered its launch in boot.py:


from switch import sw

After launching the firmware, I received a sw object, if I execute sw.change (), a software switch of the
switch to another position will occur . When the free pin closes on Vcc in the microcontroller
, the relay is turned on or off, respectively.


The next step will be the launch of the MQTT client and the ability to switch the switch from the phone.


Also popular now: