From 3df5c2149aebc77327137f2d16eec4a333be9aa7 Mon Sep 17 00:00:00 2001 From: Hendrik Langer Date: Thu, 14 Dec 2017 16:57:03 +0100 Subject: [PATCH] initial esp32 software --- README.md | 7 ++ software/platformio.ini | 11 ++- software/src/hardware.h | 11 +++ software/src/led.cpp | 9 +++ software/src/led.h | 11 +++ software/src/main.cpp | 14 +++- software/src/pusher.cpp | 46 ++++++++++++ software/src/pusher.h | 26 +++++++ software/src/webserver.cpp | 142 +++++++++++++++++++++++++++++++++++++ software/src/webserver.h | 16 +++++ software/src/wifi.cpp | 65 +++++++++++++++++ software/src/wifi.h | 21 ++++++ 12 files changed, 377 insertions(+), 2 deletions(-) create mode 100644 software/src/hardware.h create mode 100644 software/src/led.cpp create mode 100644 software/src/led.h create mode 100644 software/src/pusher.cpp create mode 100644 software/src/pusher.h create mode 100644 software/src/webserver.cpp create mode 100644 software/src/webserver.h create mode 100644 software/src/wifi.cpp create mode 100644 software/src/wifi.h diff --git a/README.md b/README.md index d8f2746..b0e2645 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,13 @@ Hints: * Align the elements so that the outer shell lines match the sliding direction * the stl files are not (yet) correctly aligned for printing. please rotate +## Software +* mkspiffs -c [src_folder] -b 4096 -p 256 -s 0x100000 spiffs.bin +* python esptool.py --chip esp32 --port [port] --baud [baud] write_flash -z 0x110000 spiffs.bin +* platformio run +* platformio run --target upload +* platformio device monitor -b 115200 + ## Contributing Feel free to remix this design and/or send pull requests to me. diff --git a/software/platformio.ini b/software/platformio.ini index 0f52080..5be8dc8 100644 --- a/software/platformio.ini +++ b/software/platformio.ini @@ -9,6 +9,15 @@ ; http://docs.platformio.org/page/projectconf.html [env:esp32dev] -platform = espressif32_stage +;platform = https://github.com/platformio/platform-espressif32.git#feature/stage +platform = espressif32 board = esp32dev framework = arduino +lib_deps = + https://github.com/me-no-dev/ESPAsyncWebServer.git + https://github.com/me-no-dev/AsyncTCP.git +; ESP Async WebServer +; AsyncTCP + FS + FastLED +lib_ignore = ESPAsyncTCP diff --git a/software/src/hardware.h b/software/src/hardware.h new file mode 100644 index 0000000..a14a958 --- /dev/null +++ b/software/src/hardware.h @@ -0,0 +1,11 @@ +#ifndef _HARDWARE_H +#define _HARDWARE_H + +#define WIFI_SSID "ssid" +#define WIFI_PASSWORD "password" + +#define LED_BUILTIN 13 + +static constexpr int SERVO_PINS[] = {22, 23, 24, 25}; + +#endif /* _HARDWARE_H */ diff --git a/software/src/led.cpp b/software/src/led.cpp new file mode 100644 index 0000000..8bd2e64 --- /dev/null +++ b/software/src/led.cpp @@ -0,0 +1,9 @@ +#include "led.h" + +using namespace std; + +Led::Led(void) { +} + +void Led::setup(void) { +} diff --git a/software/src/led.h b/software/src/led.h new file mode 100644 index 0000000..4cffa06 --- /dev/null +++ b/software/src/led.h @@ -0,0 +1,11 @@ +#ifndef _LED_H +#define _LED_H + +class Led { + public: + Led(void); + void setup(void); + private: +}; + +#endif /* _LED_H */ diff --git a/software/src/main.cpp b/software/src/main.cpp index 9d4874f..5ce53c6 100644 --- a/software/src/main.cpp +++ b/software/src/main.cpp @@ -6,14 +6,26 @@ #include -#define LED_BUILTIN 13 +#include "hardware.h" +#include "wifi.h" +#include "webserver.h" +#include "pusher.h" + +Wifi wifi; +Webserver webserver; +Pusher pusher; void setup() { Serial.begin(112500); + Serial.println("Hello"); // initialize LED digital pin as an output. pinMode(LED_BUILTIN, OUTPUT); + + wifi.connect(); + webserver.start(); + pusher.setup(); } void loop() diff --git a/software/src/pusher.cpp b/software/src/pusher.cpp new file mode 100644 index 0000000..eb8a9c5 --- /dev/null +++ b/software/src/pusher.cpp @@ -0,0 +1,46 @@ +#include +#include "esp32-hal-ledc.h" +#include "semaphore.h" + +#include "hardware.h" +#include "pusher.h" + +using namespace std; + +Pusher::Pusher(void) { + xSemaphore = xSemaphoreCreateMutex(); +} + +void Pusher::setup(void) { + int channel = 1; + int pin = 22; + for(auto pin : SERVO_PINS) { + if (xSemaphoreTake(xSemaphore, TIMEOUT) == pdTRUE) { + ledcSetup(channel, 50, TIMER_WIDTH); + ledcAttachPin(pin, channel); + ledcWrite(channel, MAX_PULSE_WIDTH); + ledcDetachPin(pin); + xSemaphoreGive(xSemaphore); + } + } +} + +void Pusher::dispense(int num) { + if (xSemaphoreTake(xSemaphore, TIMEOUT) == pdTRUE) { + int channel = 1; + int pin = SERVO_PINS[num]; + if (channel >= LEDC_NUM_CHANNELS) { + return; + } + + ledcSetup(channel, 50, TIMER_WIDTH); + ledcAttachPin(pin, channel); + ledcWrite(channel, MIN_PULSE_WIDTH); + delay(1000); + ledcWrite(channel, MAX_PULSE_WIDTH); + delay(1000); + xSemaphoreGive(xSemaphore); + } else { + return; + } +} diff --git a/software/src/pusher.h b/software/src/pusher.h new file mode 100644 index 0000000..567961f --- /dev/null +++ b/software/src/pusher.h @@ -0,0 +1,26 @@ +#ifndef _PUSHER_H +#define _PUSHER_H + +#include +#include "semaphore.h" + +static constexpr uint16_t MIN_PULSE_WIDTH = 544; // the shortest pulse sent to a servo +static constexpr uint16_t MAX_PULSE_WIDTH = 2400; // the longest pulse sent to a servo +static constexpr uint16_t DEFAULT_PULSE_WIDTH = 1500; // default pulse width + +static constexpr uint8_t LEDC_NUM_CHANNELS = 8; // default pulse width + +static constexpr TickType_t TIMEOUT = portMAX_DELAY; + +#define TIMER_WIDTH 16 + +class Pusher { + public: + Pusher(void); + void setup(void); + void dispense(int); + private: + volatile SemaphoreHandle_t xSemaphore; +}; + +#endif /* _PUSHER_H */ diff --git a/software/src/webserver.cpp b/software/src/webserver.cpp new file mode 100644 index 0000000..d25eddb --- /dev/null +++ b/software/src/webserver.cpp @@ -0,0 +1,142 @@ +#include +#include +#include +#include + +#include "webserver.h" + +using namespace std; + +Webserver::Webserver(void) + : server(80) { +} + +String processor(const String& var) +{ + if(var == "HELLO_FROM_TEMPLATE") + return F("Hello world!"); + if(var == "FACH0_NAME") + return F("Hello world!"); + if(var == "FACH1_NAME") + return F("Hello world!"); + if(var == "FACH2_NAME") + return F("Hello world!"); + return String(); +} + +const char index_html[] PROGMEM = + "Vending Machine" + "

Vending Machine

" + "" + "
%FACH0_NAME%%FACH1_NAME%%FACH2_NAME%
" + ""; // large char array, tested with 14k + +void Webserver::start(void) { + startMDNS(); + + // respond to GET requests on URL /heap + server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){ + request->send(200, "text/plain", String(ESP.getFreeHeap())); + }); + + //First request will return 0 results unless you start scan from somewhere else (loop/setup) + //Do not request more often than 3-5 seconds + server.on("/scan", HTTP_GET, [](AsyncWebServerRequest *request){ + String json = "["; + int n = WiFi.scanComplete(); + if(n == -2){ + WiFi.scanNetworks(true); + } else if(n){ + for (int i = 0; i < n; ++i){ + if(i) json += ","; + json += "{"; + json += "\"rssi\":"+String(WiFi.RSSI(i)); + json += ",\"ssid\":\""+WiFi.SSID(i)+"\""; + json += ",\"bssid\":\""+WiFi.BSSIDstr(i)+"\""; + json += ",\"channel\":"+String(WiFi.channel(i)); + json += ",\"secure\":"+String(WiFi.encryptionType(i)); +// json += ",\"hidden\":"+String(WiFi.isHidden(i)?"true":"false"); + json += "}"; + } + WiFi.scanDelete(); + if(WiFi.scanComplete() == -2){ + WiFi.scanNetworks(true); + } + } + json += "]"; + request->send(200, "text/json", json); + json = String(); + }); + + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ + request->send_P(200, "text/html", index_html, processor); + }); + + server.onNotFound([](AsyncWebServerRequest *request){ + Serial.printf("NOT_FOUND: "); + if(request->method() == HTTP_GET) + Serial.printf("GET"); + else if(request->method() == HTTP_POST) + Serial.printf("POST"); + else if(request->method() == HTTP_DELETE) + Serial.printf("DELETE"); + else if(request->method() == HTTP_PUT) + Serial.printf("PUT"); + else if(request->method() == HTTP_PATCH) + Serial.printf("PATCH"); + else if(request->method() == HTTP_HEAD) + Serial.printf("HEAD"); + else if(request->method() == HTTP_OPTIONS) + Serial.printf("OPTIONS"); + else + Serial.printf("UNKNOWN"); + Serial.printf(" http://%s%s\n", request->host().c_str(), request->url().c_str()); + + if(request->contentLength()){ + Serial.printf("_CONTENT_TYPE: %s\n", request->contentType().c_str()); + Serial.printf("_CONTENT_LENGTH: %u\n", request->contentLength()); + } + + int headers = request->headers(); + int i; + for(i=0;igetHeader(i); + Serial.printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str()); + } + + int params = request->params(); + for(i=0;igetParam(i); + if(p->isFile()){ + Serial.printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size()); + } else if(p->isPost()){ + Serial.printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); + } else { + Serial.printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); + } + } + + request->send(404); + }); + + server.begin(); + Serial.println("Webserver started."); +} + +void Webserver::startMDNS(void) { + // Set up mDNS responder: + // - first argument is the domain name, in this example + // the fully-qualified domain name is "esp8266.local" + // - second argument is the IP address to advertise + // we send our IP address on the WiFi network + if (!MDNS.begin("esp32")) { + Serial.println("Error setting up MDNS responder!"); + while(1) { + delay(1000); + } + } + Serial.println("mDNS responder started"); + + // Add service to MDNS-SD + MDNS.addService("http", "tcp", 80); +} diff --git a/software/src/webserver.h b/software/src/webserver.h new file mode 100644 index 0000000..8db33ee --- /dev/null +++ b/software/src/webserver.h @@ -0,0 +1,16 @@ +#ifndef _WEBSERVER_H +#define _WEBSERVER_H + +#include +#include + +class Webserver { + public: + Webserver(void); + void start(void); + private: + void startMDNS(void); + AsyncWebServer server; +}; + +#endif /* _WEBSERVER_H */ diff --git a/software/src/wifi.cpp b/software/src/wifi.cpp new file mode 100644 index 0000000..88c9a9b --- /dev/null +++ b/software/src/wifi.cpp @@ -0,0 +1,65 @@ +#include +#include +#include + +#include "hardware.h" +#include "wifi.h" + +using namespace std; + +Wifi::Wifi() {} + +void Wifi::reconnectTask(void* parameters) { + while(true) { + if(wifiMulti.run() != WL_CONNECTED) { + Serial.println("WiFi not connected!"); + } + vTaskDelay(3000 / portTICK_PERIOD_MS); + } + Serial.println("WiFi disconnecting!"); + WiFi.disconnect(); + vTaskDelete(NULL); +} + +void Wifi::cTaskWrapper(void* parameters) { + static_cast(parameters)->reconnectTask(NULL); +} + +void Wifi::connect() { + wifiMulti.addAP(WIFI_SSID, WIFI_PASSWORD); + + Serial.println("Connecting to WiFi network"); + if(wifiMulti.run() == WL_CONNECTED) { + Serial.println(""); + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + } + +xTaskCreate( + &cTaskWrapper, /* Task function. */ + "wifiReconnectTask", /* String with name of task. */ + 1024, /* Stack size in words. */ + this, /* Parameter passed as input of the task */ + 1, /* Priority of the task. */ + &wifiTaskHandle); /* Task handle. */ +} + +void Wifi::disconnect() { +} + +size_t Wifi::getStoredPassword(const char* ssid, char* value) { + Preferences preferences; + preferences.begin("wifi-pwd", false); + size_t len = preferences.getString(ssid, value, 64); + preferences.end(); + return len; +} + +size_t Wifi::setStoredPassword(const char* ssid, char* value) { + Preferences preferences; + preferences.begin("wifi-pwd", false); + size_t len = preferences.putString(ssid, value); + preferences.end(); + return len; +} diff --git a/software/src/wifi.h b/software/src/wifi.h new file mode 100644 index 0000000..700c30a --- /dev/null +++ b/software/src/wifi.h @@ -0,0 +1,21 @@ +#ifndef _WIFI_H +#define _WIFI_H + +#include +#include + +class Wifi { + public: + Wifi(); + void connect(); + void disconnect(); + private: + void reconnectTask(void*); + static void cTaskWrapper(void*); + WiFiMulti wifiMulti; + TaskHandle_t wifiTaskHandle; + size_t getStoredPassword(const char* ssid, char* value); + size_t setStoredPassword(const char* ssid, char* value); +}; + +#endif /* _WIFI_H */