18. July 2020

How to connect ESP8266 Wemos D1 to motor shield over I2C with MicroPython

ESP8266 Wemos D1 board has extension shield TB6612FNG which provides a connection to two motors.

The simplest way to get motors running is to connect the shield to ESP8266 and provide instructions to MicroPython repl so that ESP8266 can send instructions over I2C to TB6612FNG.

The first requirement to get the motor running is to have d1motor library.

You can download ZIP with patched d1motor library and sample code from here.

Original d1motor is available here: https://bitbucket.org/thesheep/micropython-d1motor/src/default/d1motor.py

Use rshell to copy the library on ESP8266 board.

unzip d1motor.zip
cd d1motor
rshell -p /dev/ttyUSB0
cp d1motor.py /pyboard/

Then start repl so that it’s possible to communicate with motor shield. You can exit repl by CTRL+X:

cd /pyboard/

Insert following code:

import d1motor
from machine import I2C, Pin
i2c = I2C(-1, Pin(5), Pin(4), freq=100000)
m0 = d1motor.Motor(0, i2c)
m1 = d1motor.Motor(1, i2c)

By this moment motor should start roaring and rotating. Well, that would be the happy day scenario. There are several gotchas which you may encounter.

Gotcha #1 OSError: [Errno 19] ENODEV

The code might throw ENODEV error without further explanation of what went wrong. The error means that ESP8266 was not able to find motor board via I2C. You can verify the problem by entering code:

from machine import I2C, Pin
i2c = I2C(-1, Pin(5), Pin(4), freq=100000)

The correct result should be array with 48 which is 0x30.


If you get just empty array then the boards are not able to talk over I2C:

 [ ]

The most common reason for the problem is buggy version firmware in STM32F030. You must flash it according to instructions from hackday.io.

You will need UBS2TTL module to perform flashing.

Download patched firmware: motor_shield.bin

Connect by single wire RTS with 3V3 PIN – they’re next to each other.

Connect folling wires on main part of board (not part with RTS):

3V3 - 3V3 VCC on USB2TTL
D2 - TX
D1 - RX

Install stm32flash:

sudo apt-get install stm32flash

Unlock and flash the shield:

stm32flash /dev/ttyUSB0 -k
stm32flash /dev/ttyUSB0 -u
stm32flash /dev/ttyUSB0 -v -w motor_shield.bin

After flashing unplug wires and connect the shield back to ESP8266. Run I2C scan again and you should get the correct result:

from machine import I2C, Pin
i2c = I2C(-1, Pin(5), Pin(4), freq=100000)


Gotcha #2 Standby mode not controlled by I2C

Even after the first correction, the motors might not move and there is no voltage on A1-2 or B1-2. The problem is most likely caused by Standby mode.

Check your board and you should see STBY with 3 pins and with marking I2C and IO. You need to solder top and middle pin to enable I2C control of Standby mode. Solder them and plug the board again. Now motors should start to move.

Gotcha #3 Incorrect frequency

There might be a third reason why motors are not moving: Incorrect frequency of communication via I2C. Double-check the number. One missing zero might cause the problem.

Not working configuration:

i2c = I2C(-1, Pin(5), Pin(4), freq=10000)

Working configuration:

i2c = I2C(-1, Pin(5), Pin(4), freq=100000)

Does it work? Congratulations.

Big thanks to community Radomir Dopieralski for d1motor.py, aarn_a and Matrix User for hints about Standby mode.

27. June 2020

ESP32 erase_flash failed with “Invalid head of packet”

The first step before installing MicroPython to ESP32 is to erase the flash.

I’ve installed all necessary software like esptool, but the flashing was failing with error:

esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash                                                                                                         ──(Sat,Jun27)─┘
esptool.py v2.8
Serial port /dev/ttyUSB0

A fatal error occurred: Failed to connect to ESP32: Invalid head of packet (0x1B)

The solution to the problem is to pres and hold BOOT button. Then start erase command mentioned above.

After the initial erase I was able to flash there MicroPython:

esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 esp32-idf4-20200627-unstable-v1.12-590-g9f911d822.bin

Then it was possible to connect via rshell:

rshell -p /dev/ttyUSB0                                                                                                                                          ──(Sat,Jun27)─┘
Using buffer-size of 32
Connecting to /dev/ttyUSB0 (buffer-size 32)...
Trying to connect to REPL  connected
Testing if ubinascii.unhexlify exists ... Y
Retrieving root directories ... /boot.py/
Setting time ... Jun 27, 2020 20:46:47
Evaluating board_name ... pyboard
Retrieving time epoch ... Jan 01, 2000
Welcome to rshell. Use Control-D (or the exit command) to exit rshell.

/home/georgik/projects/esp32> cd /pyboard/
/pyboard> ls

4. June 2017

Workaround: Failed to activate the platformio-ide package

PlatformIO was working without any problem, but after several updates, there was following error message:

Failed to activate the platformio-ide package

The bug is also mentioned at GitHub. It seems that the bug has a relation to the default OS shell.

Try following workaround (it worked for my Linux/ZSH):

  • change default shell to Bash
    sudo chsh -s /bin/bash YOUR_LOGIN
  • start Platform IO IDE
  • revert the shell back to your favorite
    sudo chsh -s /usr/bin/zsh YOUR_LOGIN

This solution worked for me. Let me know whether you have the same experience.

26. April 2017

How to publish topic by mosquitto_pub to Bluemix

In the previous article about LampESP, I’ve described how to subscribe ESP8266 to MQTT at Bluemix cloud. The remaining question is how to publish data.

Let’s define simple scenario for server monitoring: Server is sending every minute it’s average load to Bluemix for further processing. How to solve it?

You’ll need to create a new device type at Bluemix, let’s call it “server”. Then create new device using the same step like in the previous article.

Then you can run a simple shell script which will push all the data to Bluemix:

# Replace following values by your own
DEVICE_TOKEN="psst, something secret"

LOAD=`cat /proc/loadavg`
mosquitto_pub -h "${ORG_ID}.messaging.internetofthings.ibmcloud.com" \
-i "d:${ORG_ID}:server:${DEVICE_NAME}" \
-u use-token-auth \
-P "${DEVICE_TOKEN}" -r \
-t "iot-2/evt/${DEVICE_NAME}/fmt/text" -m "${LOAD}"

If you need more detailed information about communication just add option “-d” to mosquitto command.

Then you can check also logs from the device at Bluemix. You should see something like this:

Closed connection from YOUR_IP. The connection has completed normally.
Token auth succeeded: ClientID='d:ORG_ID:server:DEVICE_NAME', ClientIP=YOUR_IP

Please keep in mind that Bluemix requires certain format of topic name.

In the next article, we will take a closer look how to transport event from a server to ESP8266 by Node-RED.

21. April 2017

How to connect ESP8266 to Bluemix

Connecting ESP8266 by MQTT to a server like Mosquitto is relatively easy. You need just one dependency (in platformio.ini file):

lib_deps =

Code for a connection is:

WiFiClient espClient;
PubSubClient mqttClient(espClient);

static void callback(char* topicChar, byte* payloadByte, unsigned int length) {
  String topic = topicChar;

  // Default size is defined in PubSubClient library and it's limited to 128
  // https://github.com/knolleary/pubsubclient
  if (length >= MQTT_MAX_PACKET_SIZE) {
    length = MQTT_MAX_PACKET_SIZE - 1;
  snprintf(buf, length + 1, "%s", payloadByte);

  String payload = String((char *)buf);

void setup() {
  mqttClient.setServer("iot.georgik.rocks", 1883);

void reconnect() {
  if (mqttClient.connect("display")) {
  } else {
    Serial.println("Connection failed");

Code for a subscription to topic is:

void subscribeTopics() {

Code for publishing to topic is:

mqttClient.publish("other/topic/data", "123");

This works fine with Mosquitto in trusted environment. You can find sample implementation in LampESP branch v0.3 in file LampMQTT.ino.

When you switch to cloud environment you have to take in consideration security model of the cloud. E.g. Microsoft Azure IoT Hub does not support direct communication between devices. Similar limitation is true also for IBM Bluemix. The architecture of messaging must be little bit different.

How to change the code to connect to IBM Bluemix?

First of all you need to create an account in IBM Bluemix. There is 30 day trial. Then you can use part of services for free, but you have to enter your credit card. The free 370 GB-hours is sufficient to run 512 MB virtual machine during whole month for free.

Then you have to create “Internet of Things Platform” service. This service is available only in regions US and United Kingdom. The region Germany does not support this service yet. Once the service is running, go to Dashboard for your service.

You’ll be redirected to URL like: https://ORG-ID.internetofthings.ibmcloud.com/dashboard/#/boards/

There you’ll see IBM Watson IoT Platform Dashboard. Go to Devices.

Click “+ Add Device” button. Then click “Create device type”.

Click “Create device type”.

Set name e.g. to ESP8266 and proceed with registration of device type.

Once the type is ready you can define device. Click “+ Add device”. Select your type ESP8266 from drop down. Now careful!

The Next button is in lower right corner. It seems that UX engineers were not validating the interface.

Fill in the name of the device and description.

You can skip Metadata. Leave Security set to Auto-generated authentication token.

Skip summary and click Add.

Now you’ll see page with Device. The most important part is section with Authentication token.

The cloud is ready. Now it is necessary to update the code. There is a small gotcha in the server name. If you look at Watson dashboard you might think that’s the hostname for MQTT: ORG-ID.internetofthings.ibmcloud.com. You have to inject subdomain “messaging”. The correct hostname is: ORG-ID.messaging.internetofthings.ibmcloud.com.

void setup() {
  mqttClient.setServer("ORG-ID.messaging.internetofthings.ibmcloud.com", 1883);

The next important step is to add token which will be used to establish a session between the device and cloud. This is a little bit tricky. You’ll need three parameters which will be composed in the following fashion and supplied to connect method of PubSubClient:

  • id = “d:ORG-ID:ESP8266:DEVICE-NAME”
  • username = “use-token-auth”
  • password = “TOKEN-FROM-DEVICE-PAGE”
void reconnect() {
  if (mqttClient.connect(id, username, password)) {

In the case of cloud version of MQTT you could not subscribe or publish just to any random topic. You have to follow the format. In the case of subscription to command you have to use following topic: iot-2/cmd/COMMAND/fmt/json. Replace COMMAND, by any of your commands that the device should receive.

void subscribeTopics() {

To publish the device status there is also special topic:

mqttClient.publish("iot-2/evt/status/fmt/json", "{\"d\":{\"value\":\"online\"}}");

Now you’re ready to connect to the Bluemix cloud. If you experience any problems, just go to device detail and find Connection log.

Now you can connect Node-RED or other tools and communicate with the device. You can find working implementation at LampESP v0.4 project.

Let’s a make summary. There are three gotchas:

  • MQTT must be connected to subdomain: ORG-ID.messaging.internetofthings.ibmcloud.com
  • Subscription and publishing must follow specific format of topic name
  • Auth information must be composed in precisely