Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
VPavlusha committed May 27, 2023
1 parent 81403d9 commit 758c790
Show file tree
Hide file tree
Showing 29 changed files with 2,266 additions and 1 deletion.
26 changes: 26 additions & 0 deletions .github/workflows/cpp-linter.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: cpp-linter

on:
push:
paths-ignore: "doc/**"
pull_request:
paths-ignore: "doc/**"

jobs:
cpp-linter:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: cpp-linter/cpp-linter-action@master
id: linter
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
style: file

- name: Fail fast?!
if: steps.linter.outputs.checks-failed > 0
run: |
echo "Some files failed the linting checks!"
# for actual deployment
# run: exit 1
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Build results
build/

# VSCode
.vscode/

# Project
sdkconfig
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 3.16)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp32_wifi_onewire_mqtt)
75 changes: 74 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,74 @@
# ESP32_WiFi_OneWire_MQTT
[![GitHub](https://img.shields.io/github/license/VPavlusha/ESP32_WiFi_OneWire_MQTT?color=blue&label=License&logo=github)](LICENSE)
[![cpp-linter](https://github.com/VPavlusha/ESP32_WiFi_OneWire_MQTT/actions/workflows/cpp-linter.yml/badge.svg)](https://github.com/VPavlusha/ESP32_WiFi_OneWire_MQTT/actions/workflows/cpp-linter.yml)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/VPavlusha/ESP32_WiFi_OneWire_MQTT?label=Release&logo=github)](https://github.com/VPavlusha/ESP32_WiFi_OneWire_MQTT/releases)
[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua)
[![Made in Ukraine](https://img.shields.io/badge/Made_in-Ukraine-ffd700.svg?labelColor=0057b7)](https://stand-with-ukraine.pp.ua)
---

# ESP32 Wi-Fi OneWire MQTT
The ESP32 WiFi OneWire MQTT project is a simple way to read the data from DS18B20 temperature sensors connected to an ESP32 microcontroller, and send the data to an MQTT broker over Wi-Fi.<br/>
Based on: https://github.com/espressif/esp-idf

#### Table of Contents
&emsp;[1. Features](#1-features)
&emsp;[2. Monitor And Control Your Project](#2-monitor-and-control-your-project)
&emsp;[3. Getting Started](#3-getting-started)
&emsp;[4. Contributing](#4-contributing)
&emsp;[5. License](#5-license)

## 1. Features
- ESP-IDF v5.0.2
- Reading temperature data from a DS18B20 sensor using the OneWire protocol.
- Sending temperature data to an MQTT broker over Wi-Fi.
- Easy-to-use API for customizing the firmware to meet your specific needs.
- Used Wi-Fi, OneWire, DS18B20, MQTT technology.
- Written in C language.
- MIT License.

## 2. Monitor And Control Your Project
<img src="./doc/img/iot_onoff.png" alt="iot_onoff.png" width="250"/>

You have the ability to monitor and control your Internet of Things (IoT) projects with some app like [IoT OnOff](https://www.iot-onoff.com/).

## 3. Getting Started
To get started with the ESP32 WiFi OneWire MQTT project, you'll need an ESP32 microcontroller, a DS18B20 temperature sensor, and access to an MQTT broker. You'll also need to install the ESP-IDF development framework.

### 3.1 Clone the project repository:
```C
git clone https://github.com/VPavlusha/ESP32_WiFi_OneWire_MQTT.git
```
### 3.2 Customize the firmware to match your Wi-Fi, DS18B20 and MQTT settings:
- Edit the **main/Kconfig.projbuild** file with your Wi-Fi, DS18B20 and MQTT settings.

The ESP32 WiFi OneWire MQTT firmware is designed to be easily customizable. You can use the provided API to change the MQTT topic, adjust the temperature DS18B20 port connections, Wi-Fi settings and more.

### 3.3 Build the project:
```C
cd ESP32_WiFi_OneWire_MQTT
idf.py build
```
### 3.4 Flash onto your ESP32 microcontroller:
```C
idf.py -p PORT [-b BAUD] flash
```
Replace PORT with your ESP32 board’s serial port name.
You can also change the flasher baud rate by replacing BAUD with the baud rate you need. The default baud rate is 460800.<br/>
### 3.5 Monitor the output:
```C
idf.py -p <PORT> monitor
```
Do not forget to replace PORT with your serial port name.

### 3.6 Check Wi-Fi network and MQTT broker:
- Check the output on the serial monitor to verify that the ESP32 is connecting to your Wi-Fi network and MQTT broker.
- Check your MQTT broker to verify that temperature data is being sent.

More information how to build project: [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/v5.0.2/esp32/get-started/start-project.html).

## 4. Contributing
Contributions to the ESP32 WiFi OneWire MQTT project are welcome. If you find a bug or have a feature request, please submit an issue on the project's GitHub page. If you'd like to contribute code, please submit a pull request.

## 5. License
The ESP32_WiFi_OneWire_MQTT project is licensed under the MIT License. See the [MIT license] file for more information.

[MIT license]: http://www.opensource.org/licenses/mit-license.html
3 changes: 3 additions & 0 deletions components/onewire_bus/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
idf_component_register(SRCS "onewire_bus_rmt.c" "onewire_bus.c"
INCLUDE_DIRS "."
PRIV_REQUIRES driver)
90 changes: 90 additions & 0 deletions components/onewire_bus/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- |

# RMT Transmit & Receive Example -- 1-Wire bus

(See the README.md file in the upper level 'examples' directory for more information about examples.)

RMT peripheral has both transmit and receive channels. Connecting one transmit channel and one receive channel to the same GPIO and put the GPIO in open-drain mode can simulate bi-directional single wire protocols, such as [1-Wire protocol](https://www.maximintegrated.com/en/design/technical-documents/tutorials/1/1796.html).

This example demonstrates how to use RMT to simulate 1-Wire bus and read temperatrue from [DS18B20](https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf).

## How to Use Example

### Hardware Required

* A development board with any supported Espressif SOC chip (see `Supported Targets` table above)
* Several DS18B20 temperature sensors and a 4.7kohm pullup resistor

Connection :

```
┌──────────────────────────┐
│ 3.3V├───────┬─────────────┬──────────────────────┐
│ │ ┌┴┐ │VDD │VDD
│ ESP32 Board │ 4.7k│ │ ┌──────┴──────┐ ┌──────┴──────┐
│ │ └┬┘ DQ│ │ DQ│ │
│ ONEWIRE_GPIO_PIN├───────┴──┬───┤ DS18B20 │ ┌───┤ DS18B20 │ ......
│ │ └───│-------------│────┴───│-------------│──
│ │ └──────┬──────┘ └──────┬──────┘
│ │ │GND │GND
│ GND├─────────────────────┴──────────────────────┘
└──────────────────────────┘
```

The GPIO number used in this example can be changed according to your board, by the macro `EXAMPLE_ONEWIRE_GPIO_PIN` defined in [onewire_ds18b20_example_main.c](main/onewire_ds18b20_example_main.c).

*Note*: Parasite power mode is not supported currently by this example, you have to connect VDD pin to make DS18B20 functional.

### Build and Flash

Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.

(To exit the serial monitor, type ``Ctrl-]``.)

See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.

## Console Output

If there are some DS18B20s on the bus:

```
I (327) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (338) gpio: GPIO[5]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (348) onewire_rmt: RMT Tx channel created for 1-wire bus
I (358) gpio: GPIO[5]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
I (358) onewire_rmt: RMT Rx channel created for 1-wire bus
I (368) example: 1-wire bus installed
I (418) example: found device with rom id 28FF30BE21170317
I (458) example: found device with rom id 28FF297E211703A1
I (498) example: found device with rom id 28FF6F7921170352
I (508) example: 3 devices found on 1-wire bus
I (2518) example: temperature of device 28FF30BE21170317: 27.00C
I (2528) example: temperature of device 28FF297E211703A1: 26.81C
I (2538) example: temperature of device 28FF6F7921170352: 26.50C
I (3548) example: temperature of device 28FF30BE21170317: 26.94C
I (3558) example: temperature of device 28FF297E211703A1: 26.75C
I (3568) example: temperature of device 28FF6F7921170352: 26.44C
```

If there is no DS18B20 on the bus:

```
I (327) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (337) gpio: GPIO[5]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (347) onewire_rmt: RMT Tx channel created for 1-wire bus
I (357) gpio: GPIO[5]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
I (357) onewire_rmt: RMT Rx channel created for 1-wire bus
I (367) example: 1-wire bus installed
E (377) onewire_rmt: no device present on 1-wire bus
I (377) example: 0 device found on 1-wire bus
I (387) gpio: GPIO[5]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (397) gpio: GPIO[5]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (397) example: 1-wire bus deleted
```

## Troubleshooting

For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
158 changes: 158 additions & 0 deletions components/onewire_bus/onewire_bus.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "esp_check.h"
#include "esp_log.h"
#include "onewire_bus.h"

static const char *TAG = "onewire";

struct onewire_rom_search_context_t {
onewire_bus_handle_t bus_handle;

uint8_t last_device_flag;
uint16_t last_discrepancy;
uint8_t rom_number[8];
};

// Algorithm inspired by https://www.maximintegrated.com/en/design/technical-documents/app-notes/1/187.html

static const uint8_t dscrc_table[] = {
0, 94,188,226, 97, 63,221,131,194,156,126, 32,163,253, 31, 65,
157,195, 33,127,252,162, 64, 30, 95, 1,227,189, 62, 96,130,220,
35,125,159,193, 66, 28,254,160,225,191, 93, 3,128,222, 60, 98,
190,224, 2, 92,223,129, 99, 61,124, 34,192,158, 29, 67,161,255,
70, 24,250,164, 39,121,155,197,132,218, 56,102,229,187, 89, 7,
219,133,103, 57,186,228, 6, 88, 25, 71,165,251,120, 38,196,154,
101, 59,217,135, 4, 90,184,230,167,249, 27, 69,198,152,122, 36,
248,166, 68, 26,153,199, 37,123, 58,100,134,216, 91, 5,231,185,
140,210, 48,110,237,179, 81, 15, 78, 16,242,172, 47,113,147,205,
17, 79,173,243,112, 46,204,146,211,141,111, 49,178,236, 14, 80,
175,241, 19, 77,206,144,114, 44,109, 51,209,143, 12, 82,176,238,
50,108,142,208, 83, 13,239,177,240,174, 76, 18,145,207, 45,115,
202,148,118, 40,171,245, 23, 73, 8, 86,180,234,105, 55,213,139,
87, 9,235,181, 54,104,138,212,149,203, 41,119,244,170, 72, 22,
233,183, 85, 11,136,214, 52,106, 43,117,151,201, 74, 20,246,168,
116, 42,200,150, 21, 75,169,247,182,232, 10, 84,215,137,107, 53
};

uint8_t onewire_check_crc8(uint8_t *input, size_t input_size)
{
uint8_t crc8 = 0;

for (size_t i = 0; i < input_size; i ++) {
crc8 = dscrc_table[crc8 ^ input[i]];
}

return crc8;
}

esp_err_t onewire_rom_search_context_create(onewire_bus_handle_t handle, onewire_rom_search_context_handler_t *context_out)
{
ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, TAG, "invalid 1-wire handle");
ESP_RETURN_ON_FALSE(context_out, ESP_ERR_INVALID_ARG, TAG, "invalid context handler pointer");

struct onewire_rom_search_context_t *context = calloc(1, sizeof(struct onewire_rom_search_context_t));
if (!context) {
return ESP_ERR_NO_MEM;
}

context->bus_handle = handle;
*context_out = context;

return ESP_OK;
}

esp_err_t onewire_rom_search_context_delete(onewire_rom_search_context_handler_t context)
{
ESP_RETURN_ON_FALSE(context, ESP_ERR_INVALID_ARG, TAG, "invalid context handler pointer");

free(context);

return ESP_OK;
}

esp_err_t onewire_rom_search(onewire_rom_search_context_handler_t context)
{
ESP_RETURN_ON_FALSE(context, ESP_ERR_INVALID_ARG, TAG, "invalid context handler pointer");

uint8_t last_zero = 0;

if (!context->last_device_flag) {
if (onewire_bus_reset(context->bus_handle) != ESP_OK) { // no device present
return ESP_ERR_NOT_FOUND;
}

// send rom search command and start search algorithm
ESP_RETURN_ON_ERROR(onewire_bus_write_bytes(context->bus_handle, (uint8_t[]){ONEWIRE_CMD_SEARCH_ROM}, 1),
TAG, "error while sending search rom command");

for (uint16_t rom_bit_index = 0; rom_bit_index < 64; rom_bit_index ++) {
uint8_t rom_byte_index = rom_bit_index / 8;
uint8_t rom_bit_mask = 1 << (rom_bit_index % 8); // calculate byte index and bit mask in advance for convenience

uint8_t rom_bit, rom_bit_complement;
ESP_RETURN_ON_ERROR(onewire_bus_read_bit(context->bus_handle, &rom_bit), TAG, "error while reading rom bit"); // write 1 bit to read from the bus
ESP_RETURN_ON_ERROR(onewire_bus_read_bit(context->bus_handle, &rom_bit_complement),
TAG, "error while reading rom bit"); // read a bit and its complement

uint8_t search_direction;
if (rom_bit && rom_bit_complement) { // No devices participating in search.
ESP_LOGE(TAG, "no devices participating in search");
return ESP_ERR_NOT_FOUND;
} else {
if (rom_bit != rom_bit_complement) { // There are only 0s or 1s in the bit of the participating ROM numbers.
search_direction = rom_bit; // just go ahead
} else { // There are both 0s and 1s in the current bit position of the participating ROM numbers. This is a discrepancy.
if (rom_bit_index < context->last_discrepancy) { // current id bit is before the last discrepancy bit
search_direction = (context->rom_number[rom_byte_index] & rom_bit_mask) ? 0x01 : 0x00; // follow previous way
} else {
search_direction = (rom_bit_index == context->last_discrepancy) ? 0x01 : 0x00; // search for 0 bit first
}

if (search_direction == 0) { // record zero's position in last zero
last_zero = rom_bit_index;
}
}

if (search_direction == 1) { // set corrsponding rom bit by serach direction
context->rom_number[rom_byte_index] |= rom_bit_mask;
} else {
context->rom_number[rom_byte_index] &= ~rom_bit_mask;
}

ESP_RETURN_ON_ERROR(onewire_bus_write_bit(context->bus_handle, search_direction),
TAG, "error while writing direction bit"); // set search direction
}
}
} else {
ESP_LOGD(TAG, "1-wire rom search finished");
return ESP_FAIL;
}

// if the search was successful
context->last_discrepancy = last_zero;
if (context->last_discrepancy == 0) { // last zero loops back to the first bit
context->last_device_flag = true;
}

if (onewire_check_crc8(context->rom_number, 7) != context->rom_number[7]) { // check crc
ESP_LOGE(TAG, "bad crc checksum of device with id " ONEWIRE_ROM_ID_STR, ONEWIRE_ROM_ID(context->rom_number));
return ESP_ERR_INVALID_CRC;
}

return ESP_OK;
}

esp_err_t onewire_rom_get_number(onewire_rom_search_context_handler_t context, uint8_t *rom_number_out)
{
ESP_RETURN_ON_FALSE(context, ESP_ERR_INVALID_ARG, TAG, "invalid context pointer");
ESP_RETURN_ON_FALSE(rom_number_out, ESP_ERR_INVALID_ARG, TAG, "invalid rom_number pointer");

memcpy(rom_number_out, context->rom_number, sizeof(context->rom_number));

return ESP_OK;
}
Loading

0 comments on commit 758c790

Please sign in to comment.