LoRa Base Module with ATMEGA328P

I had a need to build a reliable LoRa device, in order to do some testing regarding range etc, for an upcoming project on a friend’s farm. The device needs to be ultra-cheap to manufacture, as well as little power as possible. To achieve this, I decided on using the RA-02 ( From AI Tinker, not sponsored) as well as an ATMEGA328P, which consumes very little current when put to sleep… ( The radio will be on standby the whole time though..)

Building this with a standard Arduino, or another ATMEGA powered development board can be quite messy ( as the picture below shows… )

RA-02 LoRa module with ATMEGA328P PCB – Quite messy !!

A standard Arduino will be even worse, as you need level conversion on the SPI pins, due to the fact that the RA-02 is a 3.3v device, with the GPIO, not being 5v tolerant (Yes, this is true, some other posts on Youtube and similar conveniently leave out this very important little caveat… )

This problem thus warranted a dedicated custom PCB, to be designed in stages, and thoroughly tested of course… And while doing that, I needed to design something that was modular and useable.

I came up with the following design, as a stage one prototype:

Stage 1 LoRa Base Module Prototype

The PCB is basically an Arduino Nano style PCB ( as far as IO is concerned ), with level conversion on the SPI lines ( SCK, MISO, MOSI, SS) as well as a Lora reset and IRQ pin ( which will be essential to wake up the processor later ).

As the prototype will mostly be used in the lab, with some outdoor tests later, provision was not made for battery charging circuitry. Two LDO regulators, 5v and 3.3v provide power to the ATMEGA328P and RA-02 from a DC input of 7.5 to 12v.

Level conversion is fixed at bi-directional 5v to 3v logic levels.

All unused GPIO’s are broken out onto headers.

Code can be uploaded to the MCU via ICSP or a USB-to-serial converter, as I did not add those on board, to save space and power later.

Control Pins are as follows:

RA-02 ModuleATMEGA328P
SCKD13
MISOD12
MOSID11
NSSD10
RESETD9
IQR(DIO0)D2 ( Interrupt 0 )
DIO1Not broken out on stage 1 Prototype
DIO2Not broken out on stage 1 Prototype
DIO3Not broken out on stage 1 Prototype
DIO4Not broken out on stage 1 Prototype
Pin connections between RA-02 and ATMEGA328P

The Schematic diagram are listed below

Schematic Diagram – Page 1
Schematic Diagram – Page 2
PCB – Top
PCB – Bottom

Software

The board is compatible with the LoRa library from Sandeep Mistry. Other libraries may work as well but were not tested yet.

A very basic test sketch follows below:
Note that this sketch does not have any power-saving. It is purely used to do a very basic radio test…
More detailed code will be released in later stages of the project ( more on that later )

#include <SPI.h>              // include libraries
#include <LoRa.h>

const int csPin = 10;          // LoRa radio chip select
const int resetPin = 9;       // LoRa radio reset
const int irqPin = 2;         // change for your board; must be a hardware interrupt pin

byte msgCount = 0;            // count of outgoing messages
int interval = 2000;          // interval between sends
long lastSendTime = 0;        // time of last packet send

void setup() {
  Serial.begin(9600);                   // initialize serial
  while (!Serial);

  Serial.println("LoRa Duplex - Set spreading factor");

  // override the default CS, reset, and IRQ pins (optional)
  LoRa.setPins(csPin, resetPin, irqPin); // set CS, reset, IRQ pin

  if (!LoRa.begin(433E6)) {             // initialize ratio at 433 MHz
    Serial.println("LoRa init failed. Check your connections.");
    while (true);                       // if failed, do nothing
  }

  LoRa.setSpreadingFactor(8);           // ranges from 6-12,default 7 see API docs
  Serial.println("LoRa init succeeded.");
}

void loop() {
  if (millis() - lastSendTime > interval) {
    String message = "LoRa TEST";   // send a message
    message += msgCount;
    sendMessage(message);
    Serial.println("Sending " + message);
    lastSendTime = millis();            // timestamp the message
    interval = random(2000) + 1000;    // 2-3 seconds
    msgCount++;
  }

  // parse for a packet, and call onReceive with the result:
  onReceive(LoRa.parsePacket());
}

void sendMessage(String outgoing) {
  LoRa.beginPacket();                   // start packet
  LoRa.print(outgoing);                 // add payload
  LoRa.endPacket();                     // finish packet and send it
  msgCount++;                           // increment message ID
}

void onReceive(int packetSize) {
  if (packetSize == 0) return;          // if there's no packet, return

  // read packet header bytes:
  String incoming = "";

  while (LoRa.available()) {
    incoming += (char)LoRa.read();
  }

  Serial.println("Message: " + incoming);
  Serial.println("RSSI: " + String(LoRa.packetRssi()));
  Serial.println("Snr: " + String(LoRa.packetSnr()));
  Serial.println();
}

Future Plans

Future plans for this project include the following:
– Integration of a LiPo battery charging module, with a boost converter, to enable the device to run on battery power.
– Integration with an ESP32 or similar, to build a simple GATEWAY device
– CAN-BUS controller integration, to allow for adding multiple sensors to one radio module
– IO card, with galvanically isolated inputs, as well as Relay outputs, for remote control and monitoring applications.



The PCB can be ordered, or the design files downloaded ( a free download ) from my Projects page at PCBWay soon…

This PCB was manufactured at PCBWAY. The Gerber files and BOM, as well as all the schematics, will soon be available as a shared project on their website. If you would like to have PCBWAY manufacture one of your own, designs, or even this particular PCB, you need to do the following…
1) Click on this link
2) Create an account if you have not already got one of your own.
If you use the link above, you will also instantly receive a $5USD coupon, which you can use on your first or any other order later. (Disclaimer: I will earn a small referral fee from PCBWay. This referral fee will not affect the cost of your order, nor will you pay any part thereof.)
3) Once you have gone to their website, and created an account, or login with your existing account,

4) Click on PCB Instant Quote

5) If you do not have any very special requirements for your PCB, click on Quick-order PCB

6) Click on Add Gerber File, and select your Gerber file(s) from your computer. Most of your PCB details will now be automatically selected, leaving you to only select the solder mask and silk-screen colour, as well as to remove the order number or not. You can of course fine-tune everything exactly as you want as well.

7) You can also select whether you want an SMD stencil, or have the board assembled after manufacturing. Please note that the assembly service, as well as the cost of your components, ARE NOT included in the initial quoted price. ( The quote will update depending on what options you select ).

8) When you are happy with the options that you have selected, you can click on the Save to Cart Button. From here on, you can go to the top of the screen, click on Cart, make any payment(s) or use any coupons that you have in your account.

Then just sit back and wait for your new PCB to be delivered to your door via the shipping company that you have selected during checkout.


Build your own USB-ASP Programmer Clone

Using more ATMEGA based MCU’s in my recent projects, and not using ready-made Arduino boards for any of them, it became necessary to invest in a dedicated ASP programmer to flash the MCU’s. Huge delays on electronics components, with confirmed orders being mysteriously cancelled due to sourcing issues, and the high cost of “original OEM ASP programmers”, send me on a search for a DIY style programmer, like the old “NOPPP” ( NO PARTS PIC Programmer) in the good old days…

Personal computers have changed a lot, and while ATMEGA chips are not PIC’s, I did feel that it could be done. Given the fact that you could also use an Arduino UNO as an ISP, and doing a little more digging, I finally found a very attractive alternative…

Thomas Fischl, on his website,https://www.fischl.de/usbasp, has an open-source hardware project, that seemed to be exactly what I needed. His device is capable of programming 5v devices, at various speeds, including a super slow one. He has also written firmware for the device, and although the last update was in 2011, It still seems to be working well, or at least as far as I can see…

I did however decide to add my own twist to the design and build in a logic level converter, to be able to program 3.3v devices as well…

The modified schematic is below:

Schematic Page 1
Schematic Page 2

I chose to do my own PCB layout, to incorporate the changes listed earlier, namely the logic level conversion from 5v to 3v, as well as adding a 3.3v LDO voltage regulator to provide 3.3v to the target in case it is required.

PCB Topside
PCB Bottom Side
3D Render of the PCB

The PCB is still in transit from the factory, and thus I will update this article later with pictures of the actual device.

Firmware can be flashed using any ASP programmer, Arduino as ISP as well, but with the caveat that you have to use AVRDude from the command line… More on that in the follow-up post… ( I would like to show actual screenshots of the process, and not theory.. ). The links to the firmware are available on https://www.fischl.de/usbasp, courtesy of Thomas Fischl, whom I would like to thank for making this open-source hardware project available freely, as well as for writing and maintaining the firmware.


The PCB can be ordered, or the design files downloaded ( a free download ) from my Projects page at PCBWay soon…

This PCB was manufactured at PCBWAY. The Gerber files and BOM, as well as all the schematics, will soon be available as a shared project on their website. If you would like to have PCBWAY manufacture one of your own, designs, or even this particular PCB, you need to do the following…
1) Click on this link
2) Create an account if you have not already got one of your own.
If you use the link above, you will also instantly receive a $5USD coupon, which you can use on your first or any other order later. (Disclaimer: I will earn a small referral fee from PCBWay. This referral fee will not affect the cost of your order, nor will you pay any part thereof.)
3) Once you have gone to their website, and created an account, or login with your existing account,

4) Click on PCB Instant Quote

5) If you do not have any very special requirements for your PCB, click on Quick-order PCB

6) Click on Add Gerber File, and select your Gerber file(s) from your computer. Most of your PCB details will now be automatically selected, leaving you to only select the solder mask and silk-screen colour, as well as to remove the order number or not. You can of course fine-tune everything exactly as you want as well.

7) You can also select whether you want an SMD stencil, or have the board assembled after manufacturing. Please note that the assembly service, as well as the cost of your components, ARE NOT included in the initial quoted price. ( The quote will update depending on what options you select ).

8) When you are happy with the options that you have selected, you can click on the Save to Cart Button. From here on, you can go to the top of the screen, click on Cart, make any payment(s) or use any coupons that you have in your account.

Then just sit back and wait for your new PCB to be delivered to your door via the shipping company that you have selected during checkout.




Automate your desk- or floor-standing fan

A typical desktop oscillating fan

Desk or floor-standing fans are one of those appliances that will be present in almost every home or office. Some of the newer ones may already have remote control of some sort, while the older models won’t. It is however quite easy to do a retro-fitted controller to most of them, and at the same time, give them some (limited) intelligence.

Your typical oscillating fan does not have a lot of intelligence built-in. They normally consist of an electrical motor, with three separate windings, of varying inductance ( meaning the number of turns in the coil of wire will change the magnetic field generated, thereby changing the speed of the electric motor).

These windings have one common side, where all three of them are connected together, and the other three are separated. Normally the live wire from your mains supply (220v AC in my case) will go to this common connection. The neutral wire will go to the common of a four-position mechanical switch, with each winding going to one of positions 2,3 and 4 ( This results in a 3-speed configuration, with the first switch being off). It is also VERY important to note that this mechanical switch is hardware interlocked, meaning that ONLY one switch can be on at any given time… This is to ensure that electricity can only flow through one winding at a time. If you were to send electricity through multiple windings at the same time, the motor will still work, but not for very long…

A more modern Oscillating Fan


In order to automate an oscillating fan, we would thus need a way to switch the separate windings on and off, while preventing other windings from getting power at the same time. I chose to do this with SPST relays, as a proof of concept, and plan to design it with DPDT relays at a later stage to implement a proper hardware interlock, in addition to the software interlock implemented in the control software ( more on that later)

My requirements for the device are the following:
1) Must operate from mains power, using the existing power cord of the fan.
2) Must allow for local operation of the fan using the existing control buttons.
3) Must be able to update firmware OTA, and have WiFi connectivity for control via Home Assistant or MQTT
4) Must be capable of adding support for ESP Now protocol at a later stage
5) The fan must not have any visible modifications on the outside

The 3 speed Fan controller PCB

Taking all of my requirements into consideration, I have designed the following PCB to take care of my needs. As I do not require a lot of GPIO for this ( only 3 outputs, and 3 inputs ), I have decided to use an ESP8266-12E module from Espressif ( manufactured by AITinker, not sponsored by either company). This module is relatively cheap and has more than enough flash memory, RAM, as well as GPIO available.

Circuit Diagram – Page 1
Circuit Diagram – Page 2

As we can see, the circuit is minimal, with optical isolation on the relay drivers, a programming header, and a 3-way input for the mechanical switch.

The completed PCB, wired to the oscillating fan

As seen in the picture above, the wiring is quite simple, with the neutral wire looped to the common terminal of each relay (I had only green mains rated cable available, will replace it later with a proper white cable to keep to wiring standards). Black is live, with one wire going to the mains socket, and the other to the common of the motor coil windings. Light blue, yellow and white ( connected to the N/O terminal of the relays) corresponds to speeds 1, 2 and 3 of the fan.

At the top of the board, 3 wires go to the mechanical switch and a fourth to DC ground. (Note that there is no AC voltage on any of the switches. )

Mounting the PCB in the base of the oscillating fan

The PCB is mounted in the base of the fan while taking care to ensure that no AC cables are near the DC components. The ESP8266 chip is oriented to the side ( logo side of PCB ) to prevent interference to the WiFi signal. The mechanical switch is mounted into its original position, and its wires are routed away from any AC carrying wires to prevent interference.

It is important to note here that the firmware for the PCB was uploaded before assembly. You should NOT attempt serial uploading while the device is connected to mains power under any circumstances. ( While I have taken every precaution to ensure that AC and DC components of the circuit are separated from each other, it is just common sense to not try to upload firmware with mains connected)

The completed PCB shows the Upload port near the right top corner.

Uploading firmware:

Initial uploading of firmware can be performed by connecting a USB-to-serial adapter to the UPLOAD port and providing 5v and ground from the USB-to-serial adapter. The flash button is held down, and the board is reset, after which you can proceed with uploading, alternatively, you can also connect the DTR and RTS lines from the serial adapter to automatically reset the board and enter flash mode as needed. ( If your adapter supports this of course).

ESPHome configuration

The YAML configuration for ESPHome is listed below:

esphome:
  name: esphome-web-18df94

esp8266:
  board: nodemcuv2


# Enable logging
logger:

# Enable Home Assistant API
api:

ota:


wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esphome-Web-18Df94"
    password: "verysecurepassword"

captive_portal:

sensor:
  - platform: adc
    pin: VCC
    name: "ESP8266 Chip Voltage"
    id: mcu_voltage
    unit_of_measurement: "V"
    device_class: "voltage"
    accuracy_decimals: 2
    update_interval: 60s
    
  - platform: wifi_signal
    name: "WiFi Signal Sensor"
    id: wifi_strength
    device_class: "signal_strength"
    unit_of_measurement: "dBm"
    update_interval: 240s

binary_sensor:
  - platform: gpio
    pin: 
      number: 12
      inverted: true
    name: "Fan Local Control Speed 1"
    id: "fan_local_1"
    icon: "mdi:fan-speed-1"
    filters:
      - delayed_on: 500ms
      - delayed_off: 500ms
    
    on_press:
      then:
        - switch.turn_on: speed1
    on_release:
      then:
        - switch.turn_off: speed1
  
  - platform: gpio
    pin: 
      number: 13
      inverted: true
    name: "Fan Local Control Speed 2"
    id: "fan_local_2"
    icon: "mdi:fan-speed-2"
    filters:
      - delayed_on: 500ms
      - delayed_off: 500ms
    
    on_press:
      then:
        - switch.turn_on: speed2
    on_release:
      then:
        - switch.turn_off: speed2
      
  - platform: gpio
    pin: 
      number: 14
      inverted: true
    name: "Fan Local Control Speed 3"
    id: "fan_local_3"
    icon: "mdi:fan-speed-3"
    filters:
      - delayed_on: 500ms
      - delayed_off: 500ms
    
    on_press:
      then:
        - switch.turn_on: speed3
    on_release:
      then:
        - switch.turn_off: speed3

switch:
  - platform: template
    name: "Fan Off"
    id: "fan_off"
    icon: "mdi:fan-off"
    lambda: |-
      if (id(speed1).state or id(speed2).state or id(speed3).state) {
        return false;
      } else {
        return true;
      }
    turn_on_action:
      - switch.turn_off: speed1
      - switch.turn_off: speed2
      - switch.turn_off: speed3
      

  - platform: gpio
    pin: 16
    interlock: &interlock_group [speed1, speed2, speed3]
    interlock_wait_time: 1000ms
    name: "Fan Speed 1"
    icon: "mdi:fan-speed-1"
    id: "speed1"
    inverted: true
    
    
  - platform: gpio
    pin: 5
    interlock: *interlock_group
    interlock_wait_time: 1000ms
    name: "Fan Speed 2"
    icon: "mdi:fan-speed-2"
    id: "speed2"
    inverted: true
    
  - platform: gpio
    pin: 4
    interlock: *interlock_group
    interlock_wait_time: 1000ms
    name: "Fan Speed 3"
    icon: "mdi:fan-speed-3"
    id: "speed3"
    inverted: true
    

Manufacturing the PCB

This PCB was manufactured at PCBWAY. The Gerber files and BOM, as well as all the schematics, will soon be available as a shared project on their website. If you would like to have PCBWAY manufacture one of your own, designs, or even this particular PCB, you need to do the following…
1) Click on this link
2) Create an account if you have not already got one of your own.
If you use the link above, you will also instantly receive a $5USD coupon, which you can use on your first or any other order later. (Disclaimer: I will earn a small referral fee from PCBWay. This referral fee will not affect the cost of your order, nor will you pay any part thereof.)
3) Once you have gone to their website, and created an account, or login with your existing account,

4) Click on PCB Instant Quote

5) If you do not have any very special requirements for your PCB, click on Quick-order PCB

6) Click on Add Gerber File, and select your Gerber file(s) from your computer. Most of your PCB details will now be automatically selected, leaving you to only select the solder mask and silk-screen colour, as well as to remove the order number or not. You can of course fine-tune everything exactly as you want as well.

7) You can also select whether you want an SMD stencil, or have the board assembled after manufacturing. Please note that the assembly service, as well as the cost of your components, ARE NOT included in the initial quoted price. ( The quote will update depending on what options you select ).

8) When you are happy with the options that you have selected, you can click on the Save to Cart Button. From here on, you can go to the top of the screen, click on Cart, make any payment(s) or use any coupons that you have in your account.

Then just sit back and wait for your new PCB to be delivered to your door via the shipping company that you have selected during checkout.

Remaking the STM32 Blue-Pill – Part 1

Why did I do this?
Of all the various development boards in my electronics lab, surely the most versatile, but most neglected must be the STM32 Blue Pill. Not that there is anything wrong with it, It is a very very nice board, but unfortunately, there are a few issues ( mostly personal ) that make it not jump out at me for use in a new project.

Of these, and quite similar to the Arduino Nano, and original Raspberry Pi Pico is the fact that it was designed to be mostly used on a breadboard, issues with using the USB port, wrong components installed at the factories, and needing magnification to read port numbers, made me decide to solve it in my own way.

It is also not possible to use it (the original Blue-Pill) with any of the ready-made shields for the Arduino Nano, due to different pin-outs etc. Thus requiring a mess of wires and more modules on a breadboard, or lying free on the bench, to add sensors and other devices to this particular development board…

It can be argued that its small size does make it attractive, with which I definitely do not disagree, but unlike the bigger STM32 development boards with a lot of included peripherals, or the Arduino Ecosystem, where it is possible to develop your hardware prototypes on an Arduino Uno, using various shields, and then move on to a custom PCB later, the blue pill’s development cycle seems to be very much tied to the use of a breadboard and/or modules connected with jumper wires etc…

My idea was thus to take some inspiration from the bigger STM32 Nucleo and Discovery type platforms, add very detailed, and readable pin numbers, and peripheral descriptions, as well as lay a foundation onto which I can in future design stackable shields to expand the functionality of the device.

In order to make it easier for Makers and Hobby Electronics Enthusiasts, the new PCB was designed with 0805 SMD components. These are still quite easy to solder by hand, and usually do not require the use of any special equipment (That most beginners just starting out with the hobby won’t necessarily own or have access to by default). All of this was done with the hope that more people will start using this form factor, as well as to stimulate the development of shields and add-on cards to truly bring the blue pill to the same level regarding ease-of-use that the Arduino Ecosystem currently occupies.


What changes did I make?

Blue Dev Board Schematic Diagram – MakerIot2020

The schematic diagram was not changed at all. All ports and pin numbers are 100% compatible with the original Blue Pill. Components sizes were changed from 0402 to 0805. I also made sure that the USB port would be functional, and would not require any modifications to be performed to make it useable (unlike some of the blue pill PCB’s available in Asia, which ships with a wrong value resistor at R10.

The PCB form factor has been changed to be the same size as the Arduino Uno, but with two rows of 20-pin 2.54mm headers. A more powerful 3.3v LDO regulator and additional smoothing capacitors were added. The main changes are to the silkscreen, where the pin numbering was enlarged to be more easily readable, and detailed labelling of the various possible peripherals were added. The board is also a single layer PCB, whereas the original was a double layer PCB, due to its small size.

Where and when can you get one?

The PCB is currently in production at PCBWay. When I have completed all testing of the PCB, it will be available as a PCBWay shared project, which means that you can order your own, or freely download the Manufacturing files to produce your own if you so choose. You can also contact me directly.

I plan to have completed all testing and to make available the manufacturing files, by the end of February 2022. Please be patient.

This PCB was manufactured at PCBWAY. The Gerber files and BOM, as well as all the schematics, will soon be available as a shared project on their website. If you would like to have PCBWAY manufacture one of your own, designs, or even this particular PCB, you need to do the following…
1) Click on this link
2) Create an account if you have not already got one of your own.
If you use the link above, you will also instantly receive a $5USD coupon, which you can use on your first or any other order later. (Disclaimer: I will earn a small referral fee from PCBWay. This referral fee will not affect the cost of your order, nor will you pay any part thereof.)
3) Once you have gone to their website, and created an account, or login with your existing account,

4) Click on PCB Instant Quote

5) If you do not have any very special requirements for your PCB, click on Quick-order PCB

6) Click on Add Gerber File, and select your Gerber file(s) from your computer. Most of your PCB details will now be automatically selected, leaving you to only select the solder mask and silk-screen colour, as well as to remove the order number or not. You can of course fine-tune everything exactly as you want as well.

7) You can also select whether you want an SMD stencil, or have the board assembled after manufacturing. Please note that the assembly service, as well as the cost of your components, ARE NOT included in the initial quoted price. ( The quote will update depending on what options you select ).

8) When you are happy with the options that you have selected, you can click on the Save to Cart Button. From here on, you can go to the top of the screen, click on Cart, make any payment(s) or use any coupons that you have in your account.

Then just sit back and wait for your new PCB to be delivered to your door via the shipping company that you have selected during checkout.


Port Extender Card for the MCU-8266-12E

Port Extender Card for the MCU-8266-12E IoT Controller

Introduction

After quite a few experiments, and playing with a lot of ideas, we have finally produced and tested an almost final prototype for the MCU-8266-12E IoT Controller Port Extender Card. While the baseboard already has quite a lot of free GPIO pins for additional sensors and devices, It did however have quite a few issues, namely a lack of sufficient Power outputs, difficulty access to the I2C bus, as well as only 2 relay outputs. Granted that you do have access to unused pins on the PCF8574 Port Extender, We nonetheless decided that an add-on card would definitely make sense to allow this device to really be more useable.

While looking at various ideas for this card, the most flexible seemed to be the APE Protocol device as documented in ESPHome. They used a standard Arduino board for that, but we decided that, after testing it with an Arduino Nano, since it seems to work well, let us just design a dedicated PCB. It also looks much better as well 🙂

Some Features (Aside from being a fully functional Arduino clone as well)

1). Dedicated LDO Regulators for 5v and 3.3v (800mA each), with jumpers to switch them on or off (receive power only from the IoT Motherboard).
2.) Dedicated Logic Level Converter on the I2C Bus ( This is sort of very much needed 🙂 The Atmega 328P-AU is running at 5v on this device, to enable it to run at 16Mhz.. and the ESP8266 on the Motherboard is a 3.3v device..

There are also 3x 3.3V I2C Headers, complete with 3.3v and Ground, as well as a single 5v I2C header
3). 8 Analog Inputs ( While practically you can only use 6 of these if you use I2C )
4). Voltage Divider provided on A0 to measure VIN ( to be safe, we calculated the resistors for 22v)
5). 100R current limiting resistor on A1 and A2, to measure 5v and 3.3v as well…
Analog inputs A0, A1 and A2 can be switched back to normal operation by changing the jumper at J2,J3 or J4 from On to Off.
6). 12 Digital Inputs/Outputs (14 if you use D0 and D1 as well), as well as a Jumper to remove the LED on D13.
7). Full access to the PCF8574 and ESP8266 Pins from the motherboard below.

Pictures of the PCB

Circuit Diagram

ATMega328P-AU Circuit diagram with LDO Regulators, headers and supporting circuitry.
Analog measuring circuitry, level converters and supporting circuitry and headers

Uploading Code to the ATMega328P

Uploading code to the device requires the use of either an ISCP programmer ( Arduino as ISP works well ) or in the case of a pre-boot loaded chip, a USB-to-Serial converter. We did not find it necessary to add a dedicated USB-to-Serial converter onto the PCB. It is quite easy enough to do any flashing with the tools mentioned above.


Make sure that the PCB is not stacked when doing this. ( This will prevent excessive current use of other components when you supply 5v to the PE card.


Procedure to upload using ICSP

During assembly, you are required to solder a single 90-degree bend pin header on the bottom side of the PCB, in the same hole as the board side edge of the RESET push-button. This will serve as the RESET Pin for the ISCP. Other connections are as follows:

H2 Header <- > ICSP Programmer
MOSI (E11~) – MOSI ( or Pin 11 on Arduino as ISP )
MISO (E12 ) – MISO ( or Pin 12 on Arduino as ISP )
SCK (E13) – D13 (or Pin 13 on Arduino as ISP )
RESET – D10 (or Pin 10 on Arduino as ISP )

5v and Ground from Arduino as ISP or ISCP Programmer to any 5v and ground pin on the PE Card

Please note the description above for assembly of the RESET pin header



Procedure to upload using USB-to-Serial converter

H1 Header

E0/Rx <- to Tx of USB-to-Serial converter
E1/Tx -> to Rx of USB-to-Serial converter

H2 Header

DTR <-> to DTR of USB-to-Serial converter [ This connection is needed for successful uploading. Don’t leave it out ]


5v and Ground from the USB-to-Serial converter to any 5v and ground pin on the PE Card


Testing with ESPHome APE protocol and the MCU-8266-12E IoT controller

The following Arduino Sketch needs to be uploaded to the device.
It will allow the device to function as a custom I2C device. Feel free to change the I2C address in the sketch as you choose, but remember to use the same address in your ESPHome YAML configuration file

/*
Ports:
  0 0 .. 13 13
  A0: 14, A1: 15, A2: 16, A3: 17: A4: 18: A5: 19: A6: 20, A7: 21
  port bits: 5 ... 0..32
  0:   0: 00000
  1:   1: 00001
  A7: 21: 10101
*/

#include <Arduino.h>
#include <Wire.h>

//#define DEBUG // remove debug so pin 0 and 1 can be used for IO

#define I2C_ADDRESS 8

void onRequest();
void onReceive(int);

void setup()
{
#ifdef DEBUG
  Serial.begin(115200);
  Serial.println(F("Init "));
#endif

  analogReference(INTERNAL);

  Wire.begin(I2C_ADDRESS);
  Wire.onRequest(onRequest);
  Wire.onReceive(onReceive);

#ifdef DEBUG
  Serial.println(F("Wire ok"));
#endif
}

void loop()
{
  //int temp = analogRead(A1);
  //Serial.println(temp);
}

volatile byte buffer[3];
volatile byte len = 1;

#define DIGITAL_READ(b, pin, mask) \
  if (digitalRead(pin))            \
    buffer[b] |= mask;

void readDigital()
{
  len = 3;
  buffer[0] = 0;
  DIGITAL_READ(0, 0, 1);
  DIGITAL_READ(0, 1, 2);
  DIGITAL_READ(0, 2, 4);
  DIGITAL_READ(0, 3, 8);
  DIGITAL_READ(0, 4, 16);
  DIGITAL_READ(0, 5, 32);
  DIGITAL_READ(0, 6, 64);
  DIGITAL_READ(0, 7, 128);

  buffer[1] = 0;
  DIGITAL_READ(1, 8, 1);
  DIGITAL_READ(1, 9, 2);
  DIGITAL_READ(1, 10, 4);
  DIGITAL_READ(1, 11, 8);
  DIGITAL_READ(1, 12, 16);
  DIGITAL_READ(1, 13, 32);
  DIGITAL_READ(1, A0, 64);
  DIGITAL_READ(1, A1, 128);

  buffer[2] = 0;
  DIGITAL_READ(2, A2, 1);
  DIGITAL_READ(2, A3, 2);

// I2C
//DIGITAL_READ(2, A4, 4);
//DIGITAL_READ(2, A5, 8);

// DIGITAL READ not supports on A3 .. A7
#ifdef DEBUG_READ
  Serial.print(F("Read 3 bytes: "));
  Serial.print(buffer[0]);
  Serial.print(' ');
  Serial.print(buffer[1]);
  Serial.print(' ');
  Serial.println(buffer[2]);

#endif
}
void readAnalog(int pin)
{
  int val = analogRead(A0 + pin);
  len = 2;
  buffer[0] = val & 0xFF;
  buffer[1] = (val >> 8) & 0b11;
#ifdef DEBUG_READ
  Serial.print(F("Read analog pin "));
  Serial.println(pin);
#endif
}

void onRequest()
{
  Wire.write(const_cast<uint8_t *>(buffer), len);
}

#define CMD_DIGITAL_READ 0x0

#define CMD_WRITE_ANALOG 0x2
#define CMD_WRITE_DIGITAL_HIGH 0x3
#define CMD_WRITE_DIGITAL_LOW 0x4

#define CMD_SETUP_PIN_OUTPUT 0x5
#define CMD_SETUP_PIN_INPUT_PULLUP 0x6
#define CMD_SETUP_PIN_INPUT 0x7

// 8 analog registers.. A0 to A7
// A4 and A5 not supported due to I2C
#define CMD_ANALOG_READ_A0 0b1000 // 0x8
// ....
#define CMD_ANALOG_READ_A7 0b1111 // 0xF

#define CMD_SETUP_ANALOG_INTERNAL 0x10
#define CMD_SETUP_ANALOG_DEFAULT 0x11

void onReceive(int numBytes)
{
#ifdef DEBUG_READ
  Serial.print("Received bytes: ");
  Serial.println(numBytes);
#endif
  int cmd = Wire.read();

  switch (cmd)
  {
  case CMD_DIGITAL_READ:
    readDigital();
    break;
  }

  if (cmd >= CMD_ANALOG_READ_A0 && cmd <= CMD_ANALOG_READ_A7)
  {
    readAnalog(cmd & 0b111);
    return;
  }

  int pin = Wire.read();

  switch (cmd)
  {
  case CMD_WRITE_DIGITAL_HIGH:
  case CMD_WRITE_DIGITAL_LOW:
  {
    bool output = cmd == CMD_WRITE_DIGITAL_HIGH;
    digitalWrite(pin, output);
#ifdef DEBUG
    Serial.print(F("Pin "));
    Serial.print(pin);
    Serial.println(output ? F(" HIGH") : F(" LOW"));
#endif
    break;
  }
  case CMD_WRITE_ANALOG:
  {
    int val = Wire.read() & (Wire.read() << 8);
    analogWrite(pin, val);
#ifdef DEBUG
    Serial.print(F("Pin "));
    Serial.print(pin);
    Serial.print(F(" Analog write "));
    Serial.println(val);
#endif
    break;
  }
  case CMD_SETUP_PIN_OUTPUT:
    pinMode(pin, OUTPUT);
#ifdef DEBUG
    Serial.print(F("Pin "));
    Serial.print(pin);
    Serial.println(F(" OUTPUT"));
#endif
    break;
  case CMD_SETUP_PIN_INPUT:
    pinMode(pin, INPUT);
#ifdef DEBUG
    Serial.print(F("Pin "));
    Serial.print(pin);
    Serial.println(F("INPUT"));
#endif
    break;
  case CMD_SETUP_PIN_INPUT_PULLUP:
    pinMode(pin, INPUT_PULLUP);
#ifdef DEBUG
    Serial.print(F("Pin "));
    Serial.print(pin);
    Serial.println(F("INPUT PULLUP"));
#endif
    break;
  case CMD_SETUP_ANALOG_INTERNAL:
    analogReference(INTERNAL);
#ifdef DEBUG
    Serial.println(F("Analog reference INTERNAL"));
#endif
    break;
  case CMD_SETUP_ANALOG_DEFAULT:
    analogReference(DEFAULT);
#ifdef DEBUG
    Serial.println(F("Analog reference DEFAULT"));
#endif
    break;
  }
}

The following C header file needs to be uploaded to your Home Assistant ESPHome folder.

// Must disable logging if using logging in main.cpp or in other custom components for the
//  __c causes a section type conflict with __c thingy
// you can enable logging and use it if you enable this in logger:
/*
logger:
  level: DEBUG
  esp8266_store_log_strings_in_flash: False
  */

//#define APE_LOGGING

// take advantage of LOG_ defines to decide which code to include
#ifdef LOG_BINARY_OUTPUT
#define APE_BINARY_OUTPUT
#endif
#ifdef LOG_BINARY_SENSOR
#define APE_BINARY_SENSOR
#endif
#ifdef LOG_SENSOR
#define APE_SENSOR
#endif

static const char *TAGape = "ape";

#define APE_CMD_DIGITAL_READ 0
#define APE_CMD_WRITE_ANALOG 2
#define APE_CMD_WRITE_DIGITAL_HIGH 3
#define APE_CMD_WRITE_DIGITAL_LOW 4
#define APE_CMD_SETUP_PIN_OUTPUT 5
#define APE_CMD_SETUP_PIN_INPUT_PULLUP 6
#define APE_CMD_SETUP_PIN_INPUT 7
// 8 analog registers.. A0 to A7
// A4 and A5 not supported due to I2C
#define CMD_ANALOG_READ_A0 0b1000 // 0x8
// ....
#define CMD_ANALOG_READ_A7 0b1111 // 0xF

#define CMD_SETUP_ANALOG_INTERNAL 0x10
#define CMD_SETUP_ANALOG_DEFAULT 0x11

#define get_ape(constructor) static_cast<ArduinoPortExpander *>(constructor.get_component(0))

#define ape_binary_output(ape, pin) get_ape(ape)->get_binary_output(pin)
#define ape_binary_sensor(ape, pin) get_ape(ape)->get_binary_sensor(pin)
#define ape_analog_input(ape, pin) get_ape(ape)->get_analog_input(pin)

class ArduinoPortExpander;

using namespace esphome;

#ifdef APE_BINARY_OUTPUT
class ApeBinaryOutput : public output::BinaryOutput
{
public:
  ApeBinaryOutput(ArduinoPortExpander *parent, uint8_t pin)
  {
    this->parent_ = parent;
    this->pin_ = pin;
  }
  void write_state(bool state) override;
  uint8_t get_pin() { return this->pin_; }

protected:
  ArduinoPortExpander *parent_;
  uint8_t pin_;
  // Pins are setup as output after the state is written, Arduino has no open drain outputs, after setting an output it will either sink or source thus activating outputs writen to false during a flick.
  bool setup_{true};
  bool state_{false};

  friend class ArduinoPortExpander;
};
#endif

#ifdef APE_BINARY_SENSOR
class ApeBinarySensor : public binary_sensor::BinarySensor
{
public:
  ApeBinarySensor(ArduinoPortExpander *parent, uint8_t pin)
  {
    this->pin_ = pin;
  }
  uint8_t get_pin() { return this->pin_; }

protected:
  uint8_t pin_;
};
#endif

#ifdef APE_SENSOR
class ApeAnalogInput : public sensor::Sensor
{
public:
  ApeAnalogInput(ArduinoPortExpander *parent, uint8_t pin)
  {
    this->pin_ = pin;
  }
  uint8_t get_pin() { return this->pin_; }

protected:
  uint8_t pin_;
};
#endif

class ArduinoPortExpander : public Component, public I2CDevice
{
public:
  ArduinoPortExpander(I2CBus *bus, uint8_t address, bool vref_default = false)
  {
    set_i2c_address(address);
    set_i2c_bus(bus);
    this->vref_default_ = vref_default;
  }
  void setup() override
  {
#ifdef APE_LOGGING
    ESP_LOGCONFIG(TAGape, "Setting up ArduinoPortExpander at %#02x ...", address_);
#endif

    /* We cannot setup as usual as arduino boots later than esp8266
            Poll i2c bus for our Arduino for a n seconds instead of failing fast,
            also this is important as pin setup (INPUT_PULLUP, OUTPUT it's done once)
        */
    this->configure_timeout_ = millis() + 5000;
  }
  void loop() override
  {
    if (millis() < this->configure_timeout_)
    {
      bool try_configure = millis() % 100 > 50;
      if (try_configure == this->configure_)
        return;
      this->configure_ = try_configure;

      if (ERROR_OK == this->read_register(APE_CMD_DIGITAL_READ, const_cast<uint8_t *>(this->read_buffer_), 3))
      {
#ifdef APE_LOGGING
        ESP_LOGCONFIG(TAGape, "ArduinoPortExpander found at %#02x", address_);
#endif
        delay(10);
        if (this->vref_default_)
        {
          this->write_register(CMD_SETUP_ANALOG_DEFAULT, nullptr, 0); // 0: unused
        }

        // Config success
        this->configure_timeout_ = 0;
        this->status_clear_error();
#ifdef APE_BINARY_SENSOR
        for (ApeBinarySensor *pin : this->input_pins_)
        {
          App.feed_wdt();
          uint8_t pinNo = pin->get_pin();
#ifdef APE_LOGGING
          ESP_LOGCONFIG(TAGape, "Setup input pin %d", pinNo);
#endif
          this->write_register(APE_CMD_SETUP_PIN_INPUT_PULLUP, &pinNo, 1);
          delay(20);
        }
#endif
#ifdef APE_BINARY_OUTPUT
        for (ApeBinaryOutput *output : this->output_pins_)
        {
          if (!output->setup_)
          { // this output has a valid value already
            this->write_state(output->pin_, output->state_, true);
            App.feed_wdt();
            delay(20);
          }
        }
#endif
#ifdef APE_SENSOR
        for (ApeAnalogInput *sensor : this->analog_pins_)
        {
          App.feed_wdt();
          uint8_t pinNo = sensor->get_pin();
#ifdef APE_LOGGING
          ESP_LOGCONFIG(TAGape, "Setup analog input pin %d", pinNo);
#endif
          this->write_register(APE_CMD_SETUP_PIN_INPUT, &pinNo, 1);
          delay(20);
        }
#endif
        return;
      }
      // Still not answering
      return;
    }
    if (this->configure_timeout_ != 0 && millis() > this->configure_timeout_)
    {
#ifdef APE_LOGGING
      ESP_LOGE(TAGape, "ArduinoPortExpander NOT found at %#02x", address_);
#endif
      this->mark_failed();
      return;
    }

#ifdef APE_BINARY_SENSOR
    if (ERROR_OK != this->read_register(APE_CMD_DIGITAL_READ, const_cast<uint8_t *>(this->read_buffer_), 3))
    {
#ifdef APE_LOGGING
      ESP_LOGE(TAGape, "Error reading. Reconfiguring pending.");
#endif
      this->status_set_error();
      this->configure_timeout_ = millis() + 5000;
      return;
    }
    for (ApeBinarySensor *pin : this->input_pins_)
    {
      uint8_t pinNo = pin->get_pin();

      uint8_t bit = pinNo % 8;
      uint8_t value = pinNo < 8 ? this->read_buffer_[0] : pinNo < 16 ? this->read_buffer_[1] : this->read_buffer_[2];
      bool ret = value & (1 << bit);
      if (this->initial_state_)
        pin->publish_initial_state(ret);
      else
        pin->publish_state(ret);
    }
#endif
#ifdef APE_SENSOR
    for (ApeAnalogInput *pin : this->analog_pins_)
    {
      uint8_t pinNo = pin->get_pin();
      pin->publish_state(analogRead(pinNo));
    }
#endif
    this->initial_state_ = false;
  }

#ifdef APE_SENSOR
  uint16_t analogRead(uint8_t pin)
  {
    bool ok = (ERROR_OK == this->read_register((uint8_t)(CMD_ANALOG_READ_A0 + pin), const_cast<uint8_t *>(this->read_buffer_), 2));
#ifdef APE_LOGGING
    ESP_LOGVV(TAGape, "analog read pin: %d ok: %d byte0: %d byte1: %d", pin, ok, this->read_buffer_[0], this->read_buffer_[1]);
#endif
    uint16_t value = this->read_buffer_[0] | ((uint16_t)this->read_buffer_[1] << 8);
    return value;
  }
#endif

#ifdef APE_BINARY_OUTPUT
  output::BinaryOutput *get_binary_output(uint8_t pin)
  {
    ApeBinaryOutput *output = new ApeBinaryOutput(this, pin);
    output_pins_.push_back(output);
    return output;
  }
#endif
#ifdef APE_BINARY_SENSOR
  binary_sensor::BinarySensor *get_binary_sensor(uint8_t pin)
  {
    ApeBinarySensor *binarySensor = new ApeBinarySensor(this, pin);
    input_pins_.push_back(binarySensor);
    return binarySensor;
  }
#endif
#ifdef APE_SENSOR
  sensor::Sensor *get_analog_input(uint8_t pin)
  {
    ApeAnalogInput *input = new ApeAnalogInput(this, pin);
    analog_pins_.push_back(input);
    return input;
  }
#endif
  void write_state(uint8_t pin, bool state, bool setup = false)
  {
    if (this->configure_timeout_ != 0)
      return;
#ifdef APE_LOGGING
    ESP_LOGD(TAGape, "Writing %d to pin %d", state, pin);
#endif
    this->write_register(state ? APE_CMD_WRITE_DIGITAL_HIGH : APE_CMD_WRITE_DIGITAL_LOW, &pin, 1);
    if (setup)
    {
      App.feed_wdt();
      delay(20);
#ifdef APE_LOGGING
      ESP_LOGI(TAGape, "Setup output pin %d", pin);
#endif
      this->write_register(APE_CMD_SETUP_PIN_OUTPUT, &pin, 1);
    }
  }

protected:
  bool configure_{true};
  bool initial_state_{true};
  uint8_t read_buffer_[3]{0, 0, 0};
  unsigned long configure_timeout_{5000};
  bool vref_default_{false};

#ifdef APE_BINARY_OUTPUT
  std::vector<ApeBinaryOutput *> output_pins_;
#endif
#ifdef APE_BINARY_SENSOR
  std::vector<ApeBinarySensor *> input_pins_;
#endif
#ifdef APE_SENSOR
  std::vector<ApeAnalogInput *> analog_pins_;
#endif
};

#ifdef APE_BINARY_OUTPUT
void ApeBinaryOutput::write_state(bool state)
{
  this->state_ = state;
  this->parent_->write_state(this->pin_, state, this->setup_);
  this->setup_ = false;
}
#endif

The file should be named “arduino_port_expander.h”

Make the following changes to your ESPHome YAML configuration file for the MCU-8266-12E device

esphome:
  name: mcu-8266-12e-01
  platform: ESP8266
  board: nodemcuv2
  includes:
      - arduino_port_expander.h
# Note the include file - This loads the APE Header

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:
  password: "<your password will be different - dont change it>"

wifi:
  ssid: <your ssid>
  password: <your password>

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "MCU-8266-Hotspot"
    password: "password"

captive_portal:

i2c:
# PCB Prototype
  sda: GPIO5
  scl: GPIO4
# PCB Rev 1.5 or higher, comment the above 2 lines
# and uncomment
#sda: GPIO4
#scl: GPIO5
#################### - IMPORTANT ###########
  scan: true
  id: i2c_bus_a
  
pcf8574:
  - id: 'pcf8574_hub'
    address: 0x22 # Set at 0x22, feel free to change to your liking, Remember to set the chip to the address you choose as well
    pcf8575: false

time:
  - platform: sntp
    id: ha_time
    timezone: "Etc/GMT+7"

status_led:
  pin:
    number: GPIO16
    inverted: true

#Define the APE as a custom component, taking care to ensure that:
#1). The I2C Bust ID is the same as the one you have defined in the I2C: Section
#2). The address of the APE is the same as the one you set in the sketch
    
custom_component:
  - id: ape
    lambda: |-
      auto ape_component = new ArduinoPortExpander(i2c_bus_a, 0x08,true);
      return {ape_component};
    

sensor:

  - platform: custom
    lambda: |-
      return {ape_analog_input(ape, 0),  // 1 = A1
             ape_analog_input(ape, 1),
             ape_analog_input(ape, 2)};
   
#We define 3 analog inputs (A0,A1,A2) to monitor voltages on the card
#Note that you MUST define them in the sensors section below as well AND
#THAT THEY MUST BE IN THE SAME SEQUENCE THAT YOU DEFINED THEM IN ABOVE HERE
#
#ALSO NOTE THAT YOU CAN "NOT" use A4 and A5, as they are used for I2C !
#
# As an example, of adding another 3 analog inputs, your definition above will change to:
#
#    return {ape_analog_input(ape, 0),
#           ape_analog_input(ape, 1),
#           ape_analog_input(ape, 2),
#           ape_analog_input(ape, 3),
#           ape_analog_input(ape, 6),
#           ape_analog_input(ape, 7)};
#
#
# Now define the sensors connected to these analogs below:

             
    sensors:
      - name: "PE Card VIN"
        id: analog_a0
        device_class: "voltage"
        unit_of_measurement: "v"
        accuracy_decimals: 2
        filters:
          - lambda: return x * (22.00/1023.0);
          - throttle: 60s

# We use a lambda to scale the value of VIN - Our Voltage divider was designed around 22 volt
# thus we need 22 volt here in the calculation as well to make it accurate
#
      - name: "PE Card 5v"
        id: analog_a1
        device_class: "voltage"
        unit_of_measurement: "v"
        accuracy_decimals: 2
        filters:
          - lambda: return x * (5.02/1023.0); 
          - throttle: 60s
      - name: "PE Card 3v"
        id: analog_a2
        device_class: "voltage"
        unit_of_measurement: "v"
        accuracy_decimals: 2
        filters:
          - lambda: return x * (5.02/1023.0);
          - throttle: 60s
 
# The ATMega328P 's Analog Reference is set to 5v internally, thus we need to also scale the 
# 3v input with a maximum of 5v ... 

# In case you enabled the other 3 Analog Inputs above, you need to add the following
#
#    - name: "Analog 3"
#      id: analog_a3
#      filters:
#        - throttle: 60s
#    - name: "Analog 6"
#      id: analog_a6
#      filters:
#        - throttle: 60s
#    - name: "Analog 7"
#      id: analog_a7
#      filters:
#        - throttle: 60s
#
#
             
             
             
  - platform: adc
    pin: VCC
    name: "ESP8266 Chip Voltage"
    id: mcu_voltage
    unit_of_measurement: "V"
    device_class: "voltage"
    accuracy_decimals: 2
    update_interval: 60s
    
  - platform: wifi_signal
    name: "WiFi Signal Sensor"
    id: wifi_strength
    device_class: "signal_strength"
    unit_of_measurement: "dBm"
    update_interval: 240s
    

#Digital outputs function the same

output:
- platform: custom
  type: binary
  lambda: |-
    return {ape_binary_output(ape, 2),
            ape_binary_output(ape, 3),
            ape_binary_output(ape, 4),
            ape_binary_output(ape, 5),
            ape_binary_output(ape, 6),
            ape_binary_output(ape, 7)};
  outputs:
    - id: ape_output_p2
      inverted: false
    - id: ape_output_p3
      inverted: false
    - id: ape_output_p4
      inverted: false
    - id: ape_output_p5
      inverted: false
    - id: ape_output_p6
      inverted: false
    - id: ape_output_p7
      inverted: false
      
- platform: gpio
  id: relay_1
  pin:
    pcf8574: pcf8574_hub
    number: 0
    mode: OUTPUT
    inverted: true
- platform: gpio
  id: relay_2
  pin:
    pcf8574: pcf8574_hub
    number: 1
    mode: OUTPUT
    inverted: true
- platform: gpio
  id: led_status_1
  pin:
    pcf8574: pcf8574_hub
    number: 2
    mode: OUTPUT
    inverted: true
- platform: gpio
  id: led_status_2
  pin:
    pcf8574: pcf8574_hub
    number: 3
    mode: OUTPUT
    inverted: true
      
binary_sensor:
  - platform: gpio
    id: push_button_1
    name: 'Relay1 Pushbutton'
    device_class: ''
    pin: 
      pcf8574: pcf8574_hub
      number: 4
      mode: INPUT
      inverted: true
    on_press:
      then:
        - switch.toggle: switch_relay1
        
  - platform: gpio
    id: push_button_2
    name: 'Relay2 Pushbutton'
    device_class: ''
    pin:
      pcf8574: pcf8574_hub
      number: 5
      mode: INPUT
      inverted: true
    on_press:
      #min_length: 50ms
      #max_length: 500ms
      then:
        - switch.toggle: switch_relay2
    filters:
        - delayed_on_off: 50ms
      
  

switch:
  - platform: output
    id: switch_relay1
    name: "Relay No. 1 (#0)"
    output: relay_1
    on_turn_on:
      - output.turn_on: led_status_1
    on_turn_off:
      - output.turn_off: led_status_1
      
  - platform: output
    id: switch_relay2
    name: "Relay No. 2 (#1)"
    output: relay_2
    on_turn_on:
      - output.turn_on: led_status_2
    on_turn_off:
      - output.turn_off: led_status_2
  - platform: restart
    id: reboot_switch
    name: "Reboot Me"

Detailed information on the APE is available here

Manufacturing the PCB

This PCB was manufactured at PCBWAY. The Gerber files and BOM, as well as all the schematics, will soon be available as a shared project on their website. If you would like to have PCBWAY manufacture one of your own, designs, or even this particular PCB, you need to do the following…
1) Click on this link
2) Create an account if you have not already got one of your own.
If you use the link above, you will also instantly receive a $5USD coupon, which you can use on your first or any other order later. (Disclaimer: I will earn a small referral fee from PCBWay. This referral fee will not affect the cost of your order, nor will you pay any part thereof.)
3) Once you have gone to their website, and created an account, or login with your existing account,

4) Click on PCB Instant Quote

5) If you do not have any very special requirements for your PCB, click on Quick-order PCB

6) Click on Add Gerber File, and select your Gerber file(s) from your computer. Most of your PCB details will now be automatically selected, leaving you to only select the solder mask and silk-screen colour, as well as to remove the order number or not. You can of course fine-tune everything exactly as you want as well.

7) You can also select whether you want an SMD stencil, or have the board assembled after manufacturing. Please note that the assembly service, as well as the cost of your components, ARE NOT included in the initial quoted price. ( The quote will update depending on what options you select ).

8) When you are happy with the options that you have selected, you can click on the Save to Cart Button. From here on, you can go to the top of the screen, click on Cart, make any payment(s) or use any coupons that you have in your account.

Then just sit back and wait for your new PCB to be delivered to your door via the shipping company that you have selected during checkout.

Simplifying Robotics with Raspberry Pi® RP2040

Introducing the Cytron Maker RP2040

Cytron Maker Pi RP2040 features the first microcontroller designed by Raspberry Pi – RP2040, embedded on a robot controller board. This board comes with a dual-channel DC motor driver, 4 servo motor ports and 7 Grove I/O connectors, ready for your next DIY robot/motion control project. Now you can build a robot while trying out the new RP2040 chip.

 

The DC motor driver on board is able to control 2x brushed DC motors or 1x bipolar/unipolar stepper motor rated from 3.6V to 6V, providing up to 1A current per channel continuously. The built-in Quick Test buttons and motor output LEDs allow a functional test of the motor driver in a quick and convenient way, without the need of writing any code. Vmotor for both DC and servo motors depends on the input voltage supplied to the board.


Credit: 3D robot parts designed by Camilo Parra Palacio from OttoDIY Community.
 


Credit: Self-watering Planter 3D parts on Thingiverse.
 

Maker Pi RP2040 features all the goodness of Cytron’s Maker series products. It too has lots of LEDs useful for troubleshooting (& visual effects), is able to make quite some noise with the onboard piezo buzzer and comes with push buttons ready to detect your touch.

There are three ways to supply power to the Maker Pi RP2040 – via USB (5V) socket, with a single cell LiPo/Li-Ion battery or through the VIN (3.6-6V) terminals. However, only one power source is needed to power up both controller board and motors at a time. Power supply from all these power sources can all be controlled with the power on/off switch onboard.

Cytron Maker Pi RP2040 is basically the Raspberry Pi Pico + Maker series’ goodness + Robot controller & other useful features. Therefore this board is compatible with the existing Pico ecosystem. Software, firmware, libraries and resources that are developed for Pico should work seamlessly with Cytron Maker Pi RP2040 too.

CircuitPython is preloaded on the Maker Pi RP2040 and it runs a simple demo program right out of the box. Connect it to your computer via USB micro cable and turn it on, you will be greeted by a melody tune and LEDs running light. Press GP20 and GP21 push buttons to toggle the LEDs on/off while controlling any DC and servo motors connected to it to move and stop. With this demo code, you get to test the board the moment you receive it!

While connected to your computer, a new CIRCUITPY drive appears. Explore and edit the demo code (code.py & lib folder) with any code editor you like, save any changes to the drive and you shall see it in action in no time. That’s why we embrace CircuitPython – it’s very easy to get started. Wish to use other programming languages? Sure, you are free to use MicroPython and C/C++ for Pico/RP2040. For those of you who love the Arduino ecosystem, please take a look at this official news by Arduino and also the unofficial Pico Arduino Core by Earle F. Philhower.

Features:

  • Powered by Rapberry Pi RP2040
    • Dual-core Arm Cortex-M0+ processor
    • 264KB internal RAM
    • 2MB of Flash memory
    • the exact same specifications with Raspberry Pi Pico
  • Robot controller board
    • 4x Servo motors
    • 2x DC motors with quick test buttons
  • Versatile power circuit
    • Automatic power selection: USB 5V, LiPo (1-cell) or Vin (3.6-6V)
    • Built-in 1-cell LiPo/Li-Ion charger (over-charged & over-discharged protection)
    • Power on/off switch
  • 13x Status indicator LEDs for GPIO pins
  • 1x Piezo buzzer with mute switch
  • 2x Push button
  • 2x RGB LED (Neopixel)
  • 7x Grove ports (flexible I/O options: digital, analog, I2C, SPI, UART…)
  • Preloaded with CircuitPython by default
  • Mouting holes
    • 4x 4.8mm mounting hole (LEGO® pin compatible)
    • 6x M3 screw hole

Maker Pi RP2040 VS. Maker Pi Pico?


Board Layout:

Dimension:

88mm(L) x 64mm(W) x 13mm(H)

Packing List:

Resources:

ATMega328P prototype add-on card for use with the MCU-8266-12E IoT controller.

In August of 2021, MakerIoT2020 released the MCU-8266-12E IoT Controller PCB, (part 1 is available here in case you missed that). Shortly after that, we started working on an expansion add-on card, that would work with the APE (Arduino Port Expander) protocol in ESPHome.

While I could have used a standard Arduino board for this, and in fact, I have done so during many of the testing stages,
I decided to design a custom PCB specifically for this task, in order to achieve two specific things…

1). The standard Arduino Board comes in either a 5v logic or 3v logic device. While this is perfect for many projects,
it is still sometimes required to use a logic level converter with some sensors and devices. LORA is a good example of that. As I really dislike using a breadboard, due to their inherent unreliable connections and the ever-present mess of wires going everywhere, I wanted an Arduino or ATMEGA328 based device that already has a level converter built-in.

As I could not find anything like that for sale, I decided to build my own, as you will see shortly.

2). I wanted to start moving away from using the Arduino IDE as much as possible. While the Arduino IDE is great for most tasks, It does lack in a few areas. I thus want to slowly ease myself back into using AVR C, and that requires a board that can be flashed via ICSP. ( yes, yes, you can flash an Arduino with ICSP as well. ) In the case of the planned expansion card, it would basically be a device that is flashed once and then left alone. Serial flashing would be quite unnecessary on there anyway.

The other reason, still part of point 2, is that it seems like everyone else is having all sorts of problems with fuses on the ATMega328 on custom boards etc… I wanted to see if that is really the case or not…

The PCB should also be useable as a standard “Arduino” type device to assist in prototyping and development.

ATMega328P Custom PCB – as a prototype add-on card to the MCU-8266-12E IoT controller

a Quick description of the PCB:

Standard Arduino type headers and pins are provided, with pin labels as for the Arduino Nano.
This gives us:

ATMega 328P MCU running at 16Mhz
12 Digital IO (D2 to D13) [ 14 if we use D1 and D2 as well ]
8 Analog Inputs (A0 to A7) [ A4 and A5 are used for I2C ]
ICSP header for uploading code
USB Port with CH340G for Arduino style serial flashing [This will be removed on the next version]
A Dedicated LDO 3.3v Voltage regulator, with a selectable input source (5v from USB, or directly from VIN – for high current use applications – MAX of 800mA)

An 8 Channel Bi-Directional Logic Level Converter, for now, the converter is fixed at bi-directional 3v to 5v conversion.
Additional 5v (x4), 3v (x4) and Ground pins (x8), as well as 2 general use bus connections (G1, G2) which I added for use with I2C

Led’s are provided on 5v, 3v, Serial Rx, Tx, as well as on pin D13.

Dimensions: 86mm x 51mm

Assembly – During Reflow on a hotplate.
During Reflow

Manufacturing the PCB

This PCB was manufactured at PCBWAY. The Gerber files and BOM, as well as all the schematics, will soon be available as a shared project on their website. If you would like to have PCBWAY manufacture one of your own, designs, or even this particular PCB, you need to do the following…
1) Click on this link
2) Create an account if you have not already got one of your own.
If you use the link above, you will also instantly receive a $5USD coupon, which you can use on your first or any other order later. (Disclaimer: I will earn a small referral fee from PCBWay. This referral fee will not affect the cost of your order, nor will you pay any part thereof.)
3) Once you have gone to their website, and created an account, or login with your existing account,

4) Click on PCB Instant Quote

5) If you do not have any very special requirements for your PCB, click on Quick-order PCB

6) Click on Add Gerber File, and select your Gerber file(s) from your computer. Most of your PCB details will now be automatically selected, leaving you to only select the solder mask and silk-screen colour, as well as to remove the order number or not. You can of course fine-tune everything exactly as you want as well.

7) You can also select whether you want an SMD stencil, or have the board assembled after manufacturing. Please note that the assembly service, as well as the cost of your components, ARE NOT included in the initial quoted price. ( The quote will update depending on what options you select ).

8) When you are happy with the options that you have selected, you can click on the Save to Cart Button. From here on, you can go to the top of the screen, click on Cart, make any payment(s) or use any coupons that you have in your account.

Then just sit back and wait for your new PCB to be delivered to your door via the shipping company that you have selected during checkout.

Conclusion

In conclusion, the PCB works quite well, with no issues with flashing the ATMEGA328P with an ICSP programmer from the Arduino IDE, as well as via USB from the Arduino IDE.

The level converter works as expected, successfully translating bidirectional signals on I2C and SPI to and from 3v and 5v devices.

In the next stage, we will focus on the stock APE protocol sketch, as provided by ESPHome, and then, once that is working perfectly, modify it to suit our needs.


Makrverse – A new platform for Makers

By being a part of Makrverse, you are joining a community of Makers. Makrs are the tech enthusiasts who cannot wait to have their hands on the newest inventions, the early adopters, the innovators. Makrverse is the place for everyone who wants to be a part of a making universe.

MakerIoT2020 was recently contacted by the creators of this exciting new startup. The platform aims to connect Makers and Tech Enthusiasts, thereby solving the need to get hold of the latest gadgets directly from their inventors.

If you want to know more, check out the website

Taking the next step with the IoT Controller.

With the initial prototyping of my IoT Controller now completed, and software performing as expected, I have started with the development of an add-on shield. The base device offers 2 built-in relays, and access to another 6 IO Ports on the PCF8574, as well as all the GPIO on the ESP-12E. This is all good and well and suits my initial purposes well, but

I do however now see a need to add more sensors to the device, as well as find an elegant way to power it directly from mains power, while not having lots of wires going anywhere.

So the next steps will be:

Design an add-on-shield to provide me with the following:
– Analog inputs.
 The ESP-12E has only one, and that will be very limiting in some situations.
-Digital Inputs and Outputs
 While there are still unused GPIO ports on the existing board, native to the ESP-12E,
 having the ability to connect additional devices and sensors will definitely be a good
 option to have in future.
-Some sort of Display
 Small OLED I2C displays are cheap and easy to use. I can also go full colour with an SPI
 display…

From here on, I have to decide on how and what.
I can go the discreet chip route, by using dedicated I2C chips that provide all these functions, or I can add a secondary micro-controller to the shield, which would provide more flexibility, but can also add complexity to the final design…

Please follow along and join me on the next part of this design journey. I can not promise
anything yet, but I do guarantee that it will be exciting…

Design and build an ESP8266 IoT Controller, Part 3

Welcome to Part 3 of this build. If you are new to this series, Part1 and Part2 can be found by clicking on the respective links. Today, we will look at the completed PCB for our IoT Controller. Full disclosure, There are some issues, ranging from components that have still (15 days after being ordered, not been delivered), as well as 3 minor errors on the PCB ( That is entirely my fault ). We will look at how I have overcome the problems to still end up with a functionals PCB. Please note that the errors in the PCB Artwork have BEEN CORRECTED and that the version for public download does not contain any errors. You can thus order it with confidence.

Let us get started

Errors on the PCB
Powering on the PCB
Integrating and Testing with Home Assistant
Tasmota
Order this PCB for yourself
Conclusion and Further steps

Errors on the PCB

Ground Error on C10, C11 and U2

During the design phase, I have forgotten to add a ground to the 5v regulator, and its supporting smoothing capacitors. These components were not initially included in my design, but, while added in later after I decided that since I will be designing the PCB to operate from many different voltage inputs, a reliable 5v source that is not dependent on USB power should be added… The components were added to the schematic, and I forgot to add the ground. It went undetected on the PCB design, as the Ground plane is a copper area…

In the picture above, you can see that I have temporarily fixed it with two wire links from the ground of C1, to the grounds of C10 and C11 respectively. These grounds connect back to U2.

C1 is another issue. Originally designed as a 100uf Electrolytic capacitor, I had to settle for a 10uf Tantalum. The reason being that the ordered capacitors are still floating in logistics space… with no definite ETA.

Error on I2C labelling, as well as I2C Pins at IC2

The following error was not so easy to spot. It gave me quite a headache to find. As I normally use netlabels on all the pins of any IC that I use, I have correctly labelled ESP12-E GPIO5 as SCL and GPIO4 as SDA. These netlabels were then transferred onto the PFC8574’s pins but in reverse! Note to self: Always re-read the pinout in the datasheet! To make matters worse, I flipped the SCL and SDA labels on the pin header…

How to fix:
I am fortunate that the ESP12-E, like all other ESP Modules, does not have fixed I2C pins. If this was an Atmega based project, the boards would have been useless if tracks could not be cut and reconnected!
On the ESP12-E, I2C is however software allocated to any desired GPIO pin. It was thus easily fixed by just swapping the two pins in software.

The third problem encountered is another logistics issue. This is in the process of being resolved, but, as you will soon see, is not actually a problem at all…

I have added support for an onboard USB to Serial converter, via a CH340G chip. The chip requires a 12Mhz resonator or crystal. My dear supplier accidentally sent me an 8 Mhz version. I have thus decided to depopulate the entire USB to Serial circuit, leaving just the USB Port and protection diode on the board. (To allow for powering via USB).

This does mean that programming the board becomes a little more complicated, connecting an external USB to Serial Adapter, and pressing and holding the flash button while pressing and releasing reset for each upload, followed by a manual reset afterwards. This is a pain, but, as I will be using these boards with ESPHome, only required once. All future uploads will be OTA anyway, and the correct components can be retrofitted when they arrive at a later stage.

Powering on the PCB

The PCB was first powered on with an external USB to serial converter and using the Arduino IDE, a simple sketch testing the I2C addressing of the chip, as well as the functioning of all onboard relays and LEDs.

The board was then flashed with ESPHome, using the procedure described in Part 1.
I then proceeded to measure the current required by the board, to make sure that it is as designed.

Current Requirements
Powered from 9V to 12V DC via the DC Barrel Connector

Standby, Wifi Connected to Home Assistant, All relays and LEDs off 75mA
All relays energised, status LEDs all on 255mA

Integrating and Testing with EspHome and Home Assistant

The configuration for ESPHome was updated and uploaded to the device OTA. I decided to add a monitor for the VCC input of the ESP12-E, a remote Restart button, and an external DHT11 Temperature and Humidity sensor.
The updated code is available below

esphome:
  name: iot-controller-8266-01
  platform: ESP8266
  board: nodemcuv2

# Enable logging
logger:

# Enable Home Assistant API
api:

ota:
  password: "2f8a73f47f1893f3f7baa391c4d0ba96"

wifi:
  ssid: "<your ssid>"
  password: "<your password>"

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Iot-Controller-8266-01"
    password: "y4aaH7vMITsC"

captive_portal:
#--- DO NOT COPY ANYTHING ABOVE THIS LINE ---

# when using this, you need to reassign the status LED to another GPIO
#deep_sleep:
#  run_duration: 5min
#  sleep_duration: 2min

i2c:
  sda: GPIO5
  scl: GPIO4
  scan: true
  id: i2c_bus_a
  
pcf8574:
  - id: 'pcf8574_hub'
    address: 0x22
    pcf8575: false

status_led:
    pin: 
      number: GPIO16
      inverted: true
# Reassign this LED to another GPIO when using deep sleep mode !

sensor:
# Monitor VCC on the ESP12-E
  - platform: adc
    pin: VCC
    name: "Device Input Voltage"
    unit_of_measurement: "V"
# Monitor the WiFi Signal Strength at the device
  - platform: wifi_signal
    name: "WiFi Signal Sensor"
    unit_of_measurement: "dBm"
    update_interval: 240s
# Add Temperature and Humidity Sensor
  - platform: dht
    pin: GPIO2
    temperature:
      name: "Room Temperature"
      unit_of_measurement: "°C"
      icon: "mdi:temperature"
      device_class: "temperature"
      state_class: "measurement"
      accuracy_decimals: 2
      
    humidity:
      name: "Room Humidity"
      unit_of_measurement: "%"
      icon: "mdi:water-percent"
      device_class: "humidity"
      state_class: "measurement"
      accuracy_decimals: 2
    update_interval: 60s

# Outputs to control relays and led's

output:
 - platform: gpio
   id: relay_1
   pin: 
      pcf8574: pcf8574_hub
      number: 0
      mode: OUTPUT
      inverted: true
 - platform: gpio
   id: relay_2
   pin: 
      pcf8574: pcf8574_hub
      number: 1
      mode: OUTPUT
      inverted: true
 - platform: gpio
   id: led_status_1
   pin: 
      pcf8574: pcf8574_hub
      number: 2
      mode: OUTPUT
      inverted: true
 - platform: gpio
   id: led_status_2
   pin: 
      pcf8574: pcf8574_hub
      number: 3
      mode: OUTPUT
      inverted: true
# Monitor the two local control pushbuttons on the device  
binary_sensor:
  -  platform: gpio
     id: push_button_1
     name: 'Relay1 Pushbutton'
     device_class: ''
     pin:
        pcf8574:  pcf8574_hub
        number: 4
        mode: INPUT
        inverted: true
     on_press:
      then:
        - switch.toggle: switch_relay1
     filters:
       -  delayed_on_off: 50ms
       
  -  platform: gpio
     id: push_button_2
     name: 'Relay2 Pushbutton'
     device_class: ''
     pin:
        pcf8574:  pcf8574_hub
        number: 5
        mode: INPUT
        inverted: true
     on_press:
      #min_length: 50ms
      #max_length: 500ms
      then:
        - switch.toggle: switch_relay2
     filters:
       -  delayed_on_off: 50ms

# Allow control from inside Home Assistant
     
switch:
  - platform: output 
    id: switch_relay1
    name: "Relay No. 1 (#0)"
    output: relay_1
    on_turn_on:
    - output.turn_on: led_status_1
    on_turn_off:
    - output.turn_off: led_status_1
  - platform: output 
    id: switch_relay2
    name: "Relay No. 2 (#1)"
    output: relay_2
    on_turn_on:
    - output.turn_on: led_status_2
    on_turn_off:
    - output.turn_off: led_status_2
 # Add a remote Reboot switch 
  - platform: restart
    name: "Reboot Me"

After uploading this configuration, Home Assistant was configured to reflect the changes.

Home Assistant showing the IoT Controller status ( EE Lab Area ) as well as Admin stats (Master Control Panel)

I have decided to split the different status and control outputs from the device into two cards, One in the EE Lab Area, which will later be moved into the actual room(s) where the device will be deployed, as well as on a Master Control Panel. From here, I can reboot individual devices, see their voltages and WiFi Status

Tasmota

As promised before, I did test the device with Tasmota. I had to do a custom compile to get support for the PCF8574. Performance was however VERY poor. ESPHome is snappy and quick, even in local mode. Tasmota seemed to have at least a one-second delay on doing anything.
I thus abandoned it, and won’t be making use of it in this project anymore. The flexibility of ESPHome to do what I want, how I want it, is definitely missing in Tasmota. Hopefully, that will change in the future?

Order this PCB for yourself

You can order this PCB from PCBWay as a shared Project, by clicking here.
New users will get a $5 USD coupon for use with their first order if they follow the link below to sign up for an account.

I would also like to thank Wendy at PCBWay for once again being a star. The project went smoothly and was very well produced. Make sure to consider using PCBWay for your next PCB order.

Conclusion and further steps

I am in the process of building and assembling another 2 of these devices. I have also ordered and received PolyCarbonate enclosures to mount them in. As this is an ongoing project, I still plan to add I2C temperature measurement chips to each, to measure the temperature inside the enclosure. An Air quality sensor, as well as a CO2 sensor, is also planned, with a possible Display Shield to provide test output locally at the device. This display, at the moment at least, is planned as an I2C Oled or similar. There are also plans to do an option to directly power the unit from 220V AC via an additional base-board for now, or a complete redesign, incorporating everything on one board.
Thank you for following along, I hope that you found it educational and entertaining.
Please consider joining us on Patreon. We are in the process of creating exclusive content for that platform, as well as for http://144.126.248.244. Most of the content will also remain free for all as usual.