#include <string.h>
#include <stdbool.h>
#include <WiFi.h>
#include "PubSubClient.h"
#include "ArduinoJson.h"
#include "Stepper.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
// Wifi settings and variables
String stMac;
char mac[50];
char clientId[50];
WiFiClient espClient;
// MQTT settings and variables
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqttServer = "broker.emqx.io";
int port = 1883;
PubSubClient client(espClient);
// JSON parser
DynamicJsonDocument recv_doc(256);
DynamicJsonDocument send_doc(512);
uint8_t tx_message[128] = {0};
uint8_t rx_message[128] = {0};
// Temperature variables
double temperature = 22;
// Stepper motor
uint8_t step_pin = 12, dir_pin = 13;
const uint8_t steps_per_rev = 200;
uint16_t rpm = 1; //default speed = 60 rotations per minute
Stepper stepper(steps_per_rev, dir_pin, step_pin);
// Display
#define TFT_DC 2
#define TFT_CS 15
#define BLACK 0x0000
#define WHITE 0xFFFF
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// Function declarations
uint16_t temp_to_speed(double);
uint32_t calc_steps(uint16_t, uint16_t);
void wifiConnect(){
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
}
void mqttReconnect(){
while(!client.connected()){
Serial.print("Attempting MQTT connection...");
sprintf(clientId, "system-led");
if(client.connect(clientId)){
Serial.print(clientId);
Serial.println(" connected");
client.subscribe("vasil-kolev/cooling-system/to-cooler");
}else{
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void callback(char* topic, byte* message, unsigned int length){
recv_doc.clear();
deserializeJson(recv_doc, message);
if(strstr(topic, "vasil-kolev/cooling-system/to-cooler")){
if(!strcmp(recv_doc["cmd"], "set-temp")){
if(rpm != temp_to_speed((double)recv_doc["temp"])){
char display_text[20] = {0};
sprintf(display_text, "RPM: %d", temp_to_speed((double)recv_doc["temp"]));
tft.fillScreen(BLACK);
tft.setCursor(0, 0);
tft.print(display_text);
}
temperature = (double)recv_doc["temp"];
}
}
}
void setup(){
// Begin UART debug port
Serial.begin(115200);
// Don't know what that line of code does...
randomSeed(analogRead(0));
// Connect to WIFI network
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
wifiConnect();
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.println(WiFi.macAddress());
stMac = WiFi.macAddress();
stMac.replace(":", "_");
Serial.println(stMac);
// Establish a connection to mqtt broker
client.setServer(mqttServer, port);
client.setCallback(callback);
// Setup stepper motor
stepper.setSpeed(rpm);
stepper.step(-8);
// Setup and clear TFT screen
tft.begin();
tft.setRotation(0);
tft.setCursor(0, 0);
tft.setTextSize(2);
tft.setTextColor(WHITE);
tft.fillScreen(BLACK);
// Write on screen
tft.print("Hello, world!");
tft.setTextSize(5);
}
uint16_t temp_to_speed(double temp){
uint16_t speed = 1;
if(temp >= 22 && temp <= 24){
speed = 60;
}else if(temp > 24){
speed = 120;
}
return speed;
}
uint32_t calc_steps(uint16_t rpm, uint16_t dur_ms){
uint32_t steps;
steps = (rpm * steps_per_rev * dur_ms) / 60000;
return steps;
}
void loop(){
static int8_t cnt = -1;
delay(10);
// Implement something like a wait() procedure
// In this if statement the stepper motor is
// being controlled around every second
if(++cnt >= 10){
cnt = 0;
// control stepper motor
rpm = temp_to_speed(temperature);
uint32_t steps = calc_steps(rpm, 1000);
stepper.setSpeed(rpm);
stepper.step(steps * 4);
}
// Check connection
if(!client.connected()){
mqttReconnect();
}
// Check for messages
client.loop();
}