Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mqtt_client_test #498

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pico_w/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,11 @@ if (PICO_CYW43_SUPPORTED) # set by PICO_BOARD=pico_w
else()
add_subdirectory(bt)
endif()

if (NOT TARGET picow_bt_example_no_cyw43_lwip_background)
message("Skipping Pico W Mqtt examples as support is not available")
else()
add_subdirectory(mqtt)
endif ()
endif()
endif()
8 changes: 8 additions & 0 deletions pico_w/mqtt/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.12)

project(test_mqtt C CXX ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

add_subdirectory(mqtt_client)
pico_sdk_init()
31 changes: 31 additions & 0 deletions pico_w/mqtt/mqtt_client/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@


add_executable(mqttApp
mqtt_client.c
)
target_link_libraries(mqttApp
pico_stdlib
hardware_adc
pico_cyw43_arch_lwip_threadsafe_background
pico_lwip_mqtt
)
# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)

set(PICO_BOARD pico_w CACHE STRING "Board type")
# Pull in Raspberry Pi Pico SDK (must be before project)
if (PICO_SDK_VERSION_STRING VERSION_LESS "1.4.0")
message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()
# Initialise the Raspberry Pi Pico SDK
# Add executable. Default name is the project name, version 0.1
pico_set_program_name(mqttApp "mqttApp")
pico_set_program_version(mqttApp "0.1")
pico_enable_stdio_uart(mqttApp 1)
pico_enable_stdio_usb(mqttApp 1)
target_include_directories(mqttApp PRIVATE
${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required
)

pico_add_extra_outputs(mqttApp)
90 changes: 90 additions & 0 deletions pico_w/mqtt/mqtt_client/lwipopts.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#ifndef _LWIPOPTS_EXAMPLE_COMMONH_H
#define _LWIPOPTS_EXAMPLE_COMMONH_H


// Common settings used in most of the pico_w examples
// (see https://www.nongnu.org/lwip/2_1_x/group__lwip__opts.html for details)

// allow override in some examples
#ifndef NO_SYS
#define NO_SYS 1
#endif
// allow override in some examples
#ifndef LWIP_SOCKET
#define LWIP_SOCKET 0
#endif
#if PICO_CYW43_ARCH_POLL
#define MEM_LIBC_MALLOC 1
#else
// MEM_LIBC_MALLOC is incompatible with non polling versions
#define MEM_LIBC_MALLOC 0
#endif
#define MEM_ALIGNMENT 4
#define MEM_SIZE 4000
#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL+1)
#define MEMP_NUM_TCP_SEG 32
#define MEMP_NUM_ARP_QUEUE 10
#define PBUF_POOL_SIZE 24
#define LWIP_ARP 1
#define LWIP_ETHERNET 1
#define LWIP_ICMP 1
#define LWIP_RAW 1
#define TCP_WND (8 * TCP_MSS)
#define TCP_MSS 1460
#define TCP_SND_BUF (8 * TCP_MSS)
#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1)) / (TCP_MSS))
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#define LWIP_NETIF_HOSTNAME 1
#define LWIP_NETCONN 0
#define MEM_STATS 0
#define SYS_STATS 0
#define MEMP_STATS 0
#define LINK_STATS 0
// #define ETH_PAD_SIZE 2
#define LWIP_CHKSUM_ALGORITHM 3
#define LWIP_DHCP 1
#define LWIP_IPV4 1
#define LWIP_TCP 1
#define LWIP_UDP 1
#define LWIP_DNS 1
#define LWIP_TCP_KEEPALIVE 1
#define LWIP_NETIF_TX_SINGLE_PBUF 1
#define DHCP_DOES_ARP_CHECK 0
#define LWIP_DHCP_DOES_ACD_CHECK 0

#ifndef NDEBUG
#define LWIP_DEBUG 1
#define LWIP_STATS 1
#define LWIP_STATS_DISPLAY 1
#endif

#define ETHARP_DEBUG LWIP_DBG_OFF
#define NETIF_DEBUG LWIP_DBG_OFF
#define PBUF_DEBUG LWIP_DBG_OFF
#define API_LIB_DEBUG LWIP_DBG_OFF
#define API_MSG_DEBUG LWIP_DBG_OFF
#define SOCKETS_DEBUG LWIP_DBG_OFF
#define ICMP_DEBUG LWIP_DBG_OFF
#define INET_DEBUG LWIP_DBG_OFF
#define IP_DEBUG LWIP_DBG_OFF
#define IP_REASS_DEBUG LWIP_DBG_OFF
#define RAW_DEBUG LWIP_DBG_OFF
#define MEM_DEBUG LWIP_DBG_OFF
#define MEMP_DEBUG LWIP_DBG_OFF
#define SYS_DEBUG LWIP_DBG_OFF
#define TCP_DEBUG LWIP_DBG_OFF
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
#define TCP_RTO_DEBUG LWIP_DBG_OFF
#define TCP_CWND_DEBUG LWIP_DBG_OFF
#define TCP_WND_DEBUG LWIP_DBG_OFF
#define TCP_FR_DEBUG LWIP_DBG_OFF
#define TCP_QLEN_DEBUG LWIP_DBG_OFF
#define TCP_RST_DEBUG LWIP_DBG_OFF
#define UDP_DEBUG LWIP_DBG_OFF
#define TCPIP_DEBUG LWIP_DBG_OFF
#define PPP_DEBUG LWIP_DBG_OFF
#define SLIP_DEBUG LWIP_DBG_OFF
#define DHCP_DEBUG LWIP_DBG_OFF
#endif /* __LWIPOPTS_H__ */
163 changes: 163 additions & 0 deletions pico_w/mqtt/mqtt_client/mqtt_client.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
//
// Created by elliot on 25/05/24.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment clarifying the license that this code is released under please?

//
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/irq.h"
#include "hardware/adc.h"
#include "pico/cyw43_arch.h"
#include "lwip/apps/mqtt.h"


// Temperature
#define TEMPERATURE_UNITS 'C'

// WiFi
#define WIFI_SSID "YOUR_WIFI_SSID"
#define WIFI_PASSWORD "YOUR_WIFI_PASSWD"
Comment on lines +16 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// MQTT
#define PORT 1883
#define MQTT_CLIENT_ID "clientID"
#define MQTT_BROKER_IP "YOUR_BROKER_IP"



typedef struct {
mqtt_client_t* mqtt_client_inst;
struct mqtt_connect_client_info_t mqtt_client_info;
uint8_t data[MQTT_OUTPUT_RINGBUF_SIZE];
uint8_t topic[100];
uint32_t len;
} MQTT_CLIENT_DATA_T;

MQTT_CLIENT_DATA_T *mqtt;



/* References for this implementation:
* raspberry-pi-pico-c-sdk.pdf, Section '4.1.1. hardware_adc'
* pico-examples/adc/adc_console/adc_console.c */
float read_onboard_temperature(const char unit) {

/* 12-bit conversion, assume max value == ADC_VREF == 3.3 V */
const float conversionFactor = 3.3f / (1 << 12);

float adc = (float)adc_read() * conversionFactor;
float tempC = 27.0f - (adc - 0.706f) / 0.001721f;

if (unit == 'C') {
return tempC;
} else if (unit == 'F') {
return tempC * 9 / 5 + 32;
}

return -1.0f;
}

void control_led(bool on) {
// Public state on /state topic and on/off led board
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's quite a few code-comments where you've said "Public blah blah topic" - were these supposed to say "Publish blah blah topic" ?

const char* message = on ? "On" : "Off";
if (on)
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 1);
else
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, 0);

char state_topic[128];
snprintf(state_topic, sizeof(state_topic), "%s/state", mqtt->topic);
mqtt_publish(mqtt->mqtt_client_inst, state_topic, message, strlen(message), 0, 0, NULL, NULL);
}

void publish_temperature() {
//Public temperature on /temperature topic
float temperature = read_onboard_temperature(TEMPERATURE_UNITS);
char temp_str[16];
snprintf(temp_str, sizeof(temp_str), "%.2f", temperature);
mqtt_publish(mqtt->mqtt_client_inst, "/temperature", temp_str, strlen(temp_str), 0, 0, NULL, NULL);
}
static void mqtt_incoming_data_cb(void *arg, const u8_t *data, u16_t len, u8_t flags) {
Comment on lines +76 to +77
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blank line between functions please 🙂 (both here and in a few other places)

MQTT_CLIENT_DATA_T* mqtt_client = (MQTT_CLIENT_DATA_T*)arg;
strncpy(mqtt_client->data, data, len);
mqtt_client->len = len;
mqtt_client->data[len] = '\0';
//Stampo i messaggi e i topic

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't mean to be picky, but I'm going through your code to include mqtt with my project and noticed this comment code all messed up

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, it's in Italian. It was a comment written during development, and I didn't notice it when reviewing. I'll remove it in the next commit, sorry.

printf("Topic: %s, Message: %s\n", mqtt_client->topic, mqtt_client->data);


if (strcmp(mqtt->topic, "/led") == 0)
{
if (strcmp((const char *)mqtt_client->data, "On") == 0)
control_led(true);
else if (strcmp((const char *)mqtt_client->data, "Off") == 0)
control_led(false);
}

}

static void mqtt_incoming_publish_cb(void *arg, const char *topic, u32_t tot_len) {
MQTT_CLIENT_DATA_T* mqtt_client = (MQTT_CLIENT_DATA_T*)arg;
strcpy(mqtt_client->topic, topic);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be better to use strncpy here? 🤷

}

static void mqtt_connection_cb(mqtt_client_t *client, void *arg, mqtt_connection_status_t status) {
MQTT_CLIENT_DATA_T* mqtt_client = (MQTT_CLIENT_DATA_T*)arg;
if (status == MQTT_CONNECT_ACCEPTED) {
mqtt_sub_unsub(client, "/led", 0, NULL, arg, 1);
printf("Connected to the /led topic successfully\n");
}
}
int main() {

stdio_init_all();

adc_init();
adc_set_temp_sensor_enabled(true);
adc_select_input(4);

mqtt = (MQTT_CLIENT_DATA_T*)calloc(1, sizeof(MQTT_CLIENT_DATA_T));
if (!mqtt) {
printf("Failed to inizialize MQTT client \n");
return 1;
}
// MQTT CLIENT INFO
mqtt->mqtt_client_info.client_id = MQTT_CLIENT_ID;
mqtt->mqtt_client_info.keep_alive = 60; // Keep alive in secondi

if (cyw43_arch_init()) {
printf("Failed to inizialize CYW43\n");
return 1;
}

cyw43_arch_enable_sta_mode();
if (cyw43_arch_wifi_connect_timeout_ms(WIFI_SSID, WIFI_PASSWORD, CYW43_AUTH_WPA2_AES_PSK, 10000)) {
printf("Wi-Fi error\n");
return 1;
}
printf("\nConnected to Wifi\n");

ip_addr_t addr;
if (!ip4addr_aton(MQTT_BROKER_IP, &addr)) {
printf("MQTT ip Address not valid !\n");
return 1;
}

mqtt->mqtt_client_inst = mqtt_client_new();
if (!mqtt->mqtt_client_inst) {
printf("MQTT client instance creation error\n");
return 1;
}

if (mqtt_client_connect(mqtt->mqtt_client_inst, &addr, PORT, mqtt_connection_cb, mqtt, &mqtt->mqtt_client_info) != ERR_OK) {
printf("MQTT broker connection error\n");
return 1;
}
printf("Successfully connected to the MQTT broker\n");
mqtt_set_inpub_callback(mqtt->mqtt_client_inst, mqtt_incoming_publish_cb, mqtt_incoming_data_cb, mqtt);

while (1) {
publish_temperature(); // Public temperature every 5 sec
sleep_ms(5000);
tight_loop_contents();
Comment on lines +156 to +157
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to do tight_loop_contents() if you're already doing sleep_ms(5000) on the previous line!

}

return 0;
}