basic framework
parent
c97fd6a080
commit
75fb079e46
|
@ -0,0 +1 @@
|
|||
script.sh
|
|
@ -0,0 +1,346 @@
|
|||
#!/bin/bash
|
||||
|
||||
#BASEDIR=$(dirname "$0")
|
||||
#cd "$BASEDIR"
|
||||
|
||||
# Set the IDF_PATH environment variable to point to the ESP-IDF installation
|
||||
export IDF_PATH=~/esp/esp-idf
|
||||
|
||||
version_file="version.txt"
|
||||
initial_version="1.0"
|
||||
initProject="false"
|
||||
|
||||
firmware_server_path="./firmwareserver"
|
||||
|
||||
# Function to translate text using translate-shell
|
||||
translate() {
|
||||
text="$1"
|
||||
lang="$2"
|
||||
translation=$(trans -b :"$lang" "$text")
|
||||
echo "$translation"
|
||||
}
|
||||
|
||||
# check if backup file exists and restore it
|
||||
if [ -f "$version_file.backup" ]; then
|
||||
mv "$version_file.backup" "$version_file"
|
||||
fi
|
||||
|
||||
# Check if version file exists
|
||||
if [ -f "$version_file" ]; then
|
||||
current_version=$(cat "$version_file")
|
||||
else
|
||||
echo ""
|
||||
echo ""
|
||||
read -p "Version file not found. Create version.txt with initial version $initial_version? (y/n) " create_new
|
||||
if [ "$create_new" = "y" ]; then
|
||||
echo "$initial_version" >"$version_file"
|
||||
current_version="$initial_version"
|
||||
initProject="true"
|
||||
else
|
||||
echo "Cancelling script."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# check if project is initialized
|
||||
if [ "$initProject" = "true" ]; then
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
echo "Project initialized with version $initial_version"
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
|
||||
else
|
||||
|
||||
# create backup file from version.txt
|
||||
cp "$version_file" "$version_file.backup"
|
||||
|
||||
# Ask user for input
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
read -p "Is this a bugfix update (y/n)? [y]" bug_fixes
|
||||
|
||||
if [ "$bug_fixes" = "y" ] || [ "$bug_fixes" = "" ]; then
|
||||
new_version=$(echo "$current_version + 0.1" | bc)
|
||||
|
||||
else
|
||||
echo ""
|
||||
echo ""
|
||||
read -p "Are there major changes (y/n)? [n]" major_changes
|
||||
|
||||
# Determine the version increment based on user input
|
||||
if [ "$major_changes" = "y" ]; then
|
||||
new_version=$(echo "$current_version + 1.1" | bc)
|
||||
else
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
echo "No version change needed."
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Update version in the file
|
||||
echo "$new_version" >"$version_file"
|
||||
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
echo "Update and publish firmware to version: $new_version ..."
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "building project..."
|
||||
echo ""
|
||||
|
||||
. ${IDF_PATH}/export.sh >/dev/null 2>&1
|
||||
|
||||
# Clean the build directory
|
||||
|
||||
#check if passing --clean to script
|
||||
if [ "$1" = "--clean" ]; then
|
||||
echo "cleaning project..."
|
||||
echo ""
|
||||
"$IDF_PATH/tools/idf.py" fullclean
|
||||
fi
|
||||
"$IDF_PATH/tools/idf.py" build
|
||||
|
||||
# Check if the build was successful
|
||||
if [ $? -eq 0 ]; then
|
||||
|
||||
# get project name in cmake file but the file contains multiple project texts
|
||||
project_name=$(grep -oP '(?<=project\().*(?=\))' CMakeLists.txt)
|
||||
|
||||
echo "project name: $project_name"
|
||||
|
||||
# check if project_name.bin file in ./build directory exists
|
||||
if [ -f "./build/$project_name.bin" ]; then
|
||||
echo "firmware file found: $project_name.bin"
|
||||
else
|
||||
echo "firmware file not found: $project_name.bin"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# git get current branch name
|
||||
branch_name=$(git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
# check if folder firmware_server_path exists and create if not exists
|
||||
if [ ! -d "$firmware_server_path" ]; then
|
||||
# promt user to create folder otherwise exit 1
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
echo "Folder $firmware_server_path does not exist!"
|
||||
exit 1
|
||||
fi
|
||||
# check if folder exists and create if not exist in firmware_server_path / project_name
|
||||
if [ ! -d "$firmware_server_path/$project_name" ]; then
|
||||
# promt user to create folder otherwise exit 1
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
read -p "Device $project_name does not exist! Create it? (y/n) " create_folder
|
||||
if [ "$create_folder" = "y" ]; then
|
||||
mkdir -p "$firmware_server_path/$project_name"
|
||||
else
|
||||
echo "Cancelling script."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# check if folder exists and create if not exist in firmware_server_path / project_name / branch_name
|
||||
if [ ! -d "$firmware_server_path/$project_name/$branch_name" ]; then
|
||||
# promt user to create folder otherwise exit 1
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
read -p "Branch $branch_name does not exist! Create it? (y/n) " create_folder
|
||||
if [ "$create_folder" = "y" ]; then
|
||||
mkdir -p "$firmware_server_path/$project_name/$branch_name"
|
||||
else
|
||||
echo "Cancelling script."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# copy firmware file to firmware_server_path / project_name / branch_name
|
||||
cp "./build/$project_name.bin" "$firmware_server_path/$project_name/$branch_name/firmware$new_version.bin"
|
||||
|
||||
# check if file exists and create one firmware_server_path / project_name / branch_name / info.json
|
||||
if [ ! -f "$firmware_server_path/$project_name/$branch_name/info.json" ]; then
|
||||
# promt user to create folder otherwise exit 1
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
read -p "File info.json does not exist! Create it? (y/n) " create_file
|
||||
if [ "$create_file" = "y" ]; then
|
||||
echo "creating file..."
|
||||
echo ""
|
||||
echo "{" >"$firmware_server_path/$project_name/$branch_name/info.json"
|
||||
echo " \"version\": \"$new_version\"," >>"$firmware_server_path/$project_name/$branch_name/info.json"
|
||||
echo " \"date\": \"$(date)\"" >>"$firmware_server_path/$project_name/$branch_name/info.json"
|
||||
echo "}" >>"$firmware_server_path/$project_name/$branch_name/info.json"
|
||||
else
|
||||
echo "Cancelling script."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# check if ./changelog_en.txt exists If not exists create empty file
|
||||
if [ ! -f "./changelog_en.txt" ]; then
|
||||
echo "creating changelog_en.txt..."
|
||||
echo "" >"./changelog_en.txt"
|
||||
fi
|
||||
|
||||
# read changelog_en.txt
|
||||
changes_en=$(cat "./changelog_en.txt")
|
||||
|
||||
# check if changes_en is empty or contains no letters or numbers
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
|
||||
if [ -z "$changes_en" ] || [ ! -n "$(echo "$changes_en" | sed -e 's/[[:space:]]//g')" ]; then
|
||||
|
||||
echo "Enter quick changes:"
|
||||
echo ""
|
||||
read -p "English: " changes_en
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
else
|
||||
changesFromFile="true"
|
||||
fi
|
||||
|
||||
echo "English changes:"
|
||||
echo "$changes_en"
|
||||
|
||||
changes_de=$(translate "$changes_en" de)
|
||||
echo ""
|
||||
echo "German changes:"
|
||||
echo "$changes_de"
|
||||
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
|
||||
# check if var "changesFromFile" is true
|
||||
|
||||
if [ "$changesFromFile" = "true" ]; then
|
||||
# ask to agree or edit changes
|
||||
read -p "Do you agree with the changes? (y/n) [y]" agree_changes
|
||||
if [ "$agree_changes" != "y" ] && [ "$agree_changes" != "" ]; then
|
||||
echo "Enter changes:"
|
||||
echo ""
|
||||
read -p "English: " changes_en
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
echo "English changes:"
|
||||
echo "$changes_en"
|
||||
echo ""
|
||||
changes_de=$(translate "$changes_en" de)
|
||||
|
||||
echo "German changes:"
|
||||
echo "$changes_de"
|
||||
echo ""
|
||||
changesFromFile="false"
|
||||
fi
|
||||
fi
|
||||
|
||||
# if changes entered ask to agree or discard
|
||||
if [ ! -z "$changes_de" ] || [ ! -z "$changes_en" ]; then
|
||||
if [ "$changesFromFile" != "true" ]; then
|
||||
read -p "Do you agree with the changes? (y/n) " agree_changes
|
||||
fi
|
||||
|
||||
if [ "$changesFromFile" = "true" ] || [ "$agree_changes" = "y" ]; then
|
||||
|
||||
# escape to json in $changes_de and $changes_en
|
||||
changes_de_escaped=$(echo "$changes_de" | sed ':a;N;$!ba;s/\n/\\n/g')
|
||||
changes_en_escaped=$(echo "$changes_en" | sed ':a;N;$!ba;s/\n/\\n/g')
|
||||
|
||||
# check if file exists and create one firmware_server_path / project_name / branch_name / changelog.json
|
||||
if [ ! -f "$firmware_server_path/$project_name/$branch_name/changelog.json" ]; then
|
||||
# create file with content {}
|
||||
echo "{}" >"$firmware_server_path/$project_name/$branch_name/changelog.json"
|
||||
fi
|
||||
|
||||
# update version in changelog.json: add {version:{"de": "changes", "en": "changes"}} to the root {}
|
||||
echo "updating changelog.json..."
|
||||
|
||||
new_entry="{\"de\": \"$changes_de_escaped\", \"en\": \"$changes_en_escaped\"}"
|
||||
jq --arg new_version "$new_version" --argjson new_entry "$new_entry" \
|
||||
'. * {($new_version): $new_entry}' \
|
||||
"$firmware_server_path/$project_name/$branch_name/changelog.json" >output.json
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
mv output.json "$firmware_server_path/$project_name/$branch_name/changelog.json"
|
||||
|
||||
#create changelogs folder if not exists
|
||||
if [ ! -d "./changelogs" ]; then
|
||||
mkdir "./changelogs"
|
||||
fi
|
||||
|
||||
if [ "$changesFromFile" = "true" ]; then
|
||||
|
||||
mv "changelog_en.txt" "./changelogs/$project_name-$new_version-en.txt"
|
||||
touch "changelog_en.txt"
|
||||
else
|
||||
# write changes_en to "./changelogs/$project_name-$new_version-en.txt"
|
||||
echo "$changes_en" >"./changelogs/$project_name-$new_version-en.txt"
|
||||
fi
|
||||
else
|
||||
rm output.json
|
||||
echo ""
|
||||
echo ""
|
||||
echo "Error updating changelog.json!!!!"
|
||||
fi
|
||||
|
||||
# translate changes_en to changes_de
|
||||
|
||||
else
|
||||
echo "Cancelling script."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# update version in info.json
|
||||
echo "updating info.json..."
|
||||
|
||||
sed -i "s/\"version\": \".*\"/\"version\": \"$new_version\"/g" "$firmware_server_path/$project_name/$branch_name/info.json"
|
||||
sed -i "s/\"date\": \".*\"/\"date\": \"$(date)\"/g" "$firmware_server_path/$project_name/$branch_name/info.json"
|
||||
|
||||
#remove old version file
|
||||
rm "$version_file.backup"
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
echo "Build successful :-) Firmware published!"
|
||||
|
||||
exit 0
|
||||
else
|
||||
# Restore the version file from backup
|
||||
mv "$version_file.backup" "$version_file"
|
||||
|
||||
echo ""
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
echo ""
|
||||
echo "Build failed. Firmware will NOT be published!"
|
||||
echo ""
|
||||
echo "###############################################"
|
||||
exit 1
|
||||
fi
|
|
@ -1,2 +1,26 @@
|
|||
idf_component_register(SRCS "src/jannex.c" "src/ota.c"
|
||||
INCLUDE_DIRS "include")
|
||||
|
||||
file(GLOB_RECURSE SRCS
|
||||
"src/*.c" # Include all .c files in src directory
|
||||
"src/api/*.c" # Include all .c files in src/api directory
|
||||
)
|
||||
|
||||
idf_component_register(
|
||||
SRCS "${SRCS}"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES
|
||||
app_update
|
||||
esp_http_client
|
||||
esp_https_ota
|
||||
app_update
|
||||
nvs_flash
|
||||
esp_http_client
|
||||
mbedtls
|
||||
esp_netif
|
||||
esp_http_server
|
||||
esp_wifi
|
||||
lwip
|
||||
)
|
||||
|
||||
set_target_properties(${COMPONENT_LIB} PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
)
|
|
@ -20,41 +20,12 @@ menu "Jannex Configuration"
|
|||
|
||||
config ESP_OTA_SERVER
|
||||
string "OTA Server domain"
|
||||
default ""
|
||||
default "mcu.ex.umbach.dev"
|
||||
help
|
||||
Enter the URL
|
||||
|
||||
choice FIRMWARE_BRANCH
|
||||
prompt "Select branch"
|
||||
default SELECTION_MASTER
|
||||
help
|
||||
Choose default branch.
|
||||
|
||||
config SELECTION_MASTER
|
||||
bool "master"
|
||||
|
||||
config SELECTION_BETA
|
||||
bool "beta"
|
||||
|
||||
config SELECTION_STABLE
|
||||
bool "stable"
|
||||
|
||||
config SELECTION_PRODUCTION
|
||||
bool "production"
|
||||
|
||||
config SELECTION_CUSTOM
|
||||
bool "Enter custom branch"
|
||||
|
||||
endchoice
|
||||
|
||||
config FIRMWARE_BRANCH_CUSTOM
|
||||
string "Enter branch name"
|
||||
depends on SELECTION_CUSTOM
|
||||
help
|
||||
Enter custom branch
|
||||
Enter the URL without htts:// or http:// and max 48 characters!
|
||||
|
||||
config FIRMWARE_UPDATE_SCAN
|
||||
default 10
|
||||
default y
|
||||
bool "Scan interval for updates"
|
||||
help
|
||||
Scans the ota server for new updates.
|
||||
|
@ -62,10 +33,46 @@ menu "Jannex Configuration"
|
|||
config FIRMWARE_UPDATE_SCAN_SECONDS
|
||||
default 10
|
||||
int "Scan interval for updates (in Seconds)"
|
||||
range 1 604800
|
||||
depends on FIRMWARE_UPDATE_SCAN
|
||||
help
|
||||
Enter 0 to disable
|
||||
|
||||
|
||||
config HTTP_SERVER
|
||||
bool "Enable HTTP Server"
|
||||
default y
|
||||
help
|
||||
Enable HTTP Server
|
||||
|
||||
config HTTP_SERVER_PORT
|
||||
default 80
|
||||
int "HTTP Server Port"
|
||||
depends on HTTP_SERVER
|
||||
|
||||
config HTTP_SERVER_ENABLE_DEBUG_MODE
|
||||
bool "Enable HTTP Server Debug Mode"
|
||||
default y
|
||||
help
|
||||
Enable HTTP Server Console. It is used for remote debugging and redirects ESP_LOG to Socket Server
|
||||
|
||||
|
||||
config HTTP_SERVER_DEBUG_URL
|
||||
string "HTTP Server Debug Port"
|
||||
default "ws://con.ex.umbach.dev/mcu"
|
||||
depends on HTTP_SERVER_ENABLE_DEBUG_MODE
|
||||
|
||||
config HTTP_SERVER_DEBUG_PORT
|
||||
default 50088
|
||||
int "HTTP Server Debug Port"
|
||||
depends on HTTP_SERVER_ENABLE_DEBUG_MODE
|
||||
|
||||
config HTTP_SERVER_DEBUG_CACHE_LENGTH
|
||||
default 4000
|
||||
int "HTTP Server Debug Cache Length"
|
||||
depends on HTTP_SERVER_ENABLE_DEBUG_MODE
|
||||
help
|
||||
The length of the debug cache. The cache is used to store the last debug chars. The cache is used to send the last debug chars to the client when the client connects to the debug server or when the client reconnects to the debug server.
|
||||
|
||||
config NTP_SERVER
|
||||
string "NTP Server"
|
||||
default "0.de.pool.ntp.org"
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
BASEDIR=$(dirname "$0")
|
||||
cd "$BASEDIR"
|
||||
|
||||
firmware_server="https://mcu.ex.umbach.dev"
|
||||
upload_server="https://firmwareuploadserver.ex.umbach.dev"
|
||||
key="yhQ2y8Y6xPqxXHzMO2BNUHwxmy9x3APXOJ0qzWRmkqX7CXWcrpCxLQLzPxDEB0FZ"
|
||||
|
||||
rm script.sh
|
||||
curl -s -o script.sh $upload_server/getFirmwareUScript?key=$key
|
||||
sh script.sh $key $upload_server $firmware_server
|
|
@ -1,2 +1,6 @@
|
|||
version: '0.0.1'
|
||||
description: 'This is a test component'
|
||||
|
||||
dependencies:
|
||||
espressif/esp_websocket_client: "^1.0.1"
|
||||
espressif/json_parser: "^1.0.3"
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "esp_system.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#ifndef CONFIG_ESP_WIFI_SSID
|
||||
#error "WIFI SSID is not defined!"
|
||||
#endif
|
||||
|
||||
static const char *jannexTAG = "JANNEX";
|
||||
|
||||
void initJannex();
|
||||
void updateJannex();
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "jannex/jannex.h"
|
||||
|
||||
#ifdef CONFIG_HTTP_SERVER_ENABLE_DEBUG_MODE
|
||||
|
||||
#define PORT 3333
|
||||
#define KEEPALIVE_IDLE 5 // Keep-alive idle time. In idle time without receiving any data from peer, will send keep-alive probe packet
|
||||
#define KEEPALIVE_INTERVAL 5 // Keep-alive probe packet interval time
|
||||
#define KEEPALIVE_COUNT 3 // Keep-alive probe packet retry count
|
||||
|
||||
void initConsole();
|
||||
void connectConsole();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <esp_http_server.h>
|
||||
|
||||
// Define the function pointer type for the custom API handler
|
||||
typedef void (*CustomAPIHandler)(httpd_handle_t server);
|
||||
|
||||
// Global instance of the custom API context
|
||||
extern CustomAPIHandler g_customAPIContext;
|
||||
|
||||
// Function to set the custom API handler
|
||||
void setCustomAPIHandler(CustomAPIHandler handler);
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
esp_err_t https_get_request_SYNC(const char *url, char *out_buffer, int *out_buffer_length, int out_buffer_size, int *status_code);
|
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
void initStorage();
|
||||
void defaultValuesToStorage();
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
#include "jannex/initStorage.h"
|
||||
#include "jannex/storage.h"
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
#define CONFIG_ESP_WIFI_AP
|
||||
#define CONFIG_HTTP_SERVER_ENABLE_DEBUG_MODE
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
#if defined(CONFIG_ESP_WIFI_SSID) || defined(CONFIG_ESP_WIFI_AP)
|
||||
|
||||
/* The event group allows multiple bits for each event, but we only care about two events:
|
||||
* - we are connected to the AP with an IP
|
||||
* - we failed to connect after the maximum amount of retries */
|
||||
#define NETWORK_CONNECTED_BIT BIT0
|
||||
#define NETWORK_FAIL_BIT BIT1
|
||||
|
||||
/* FreeRTOS event group to signal when we are connected*/
|
||||
static EventGroupHandle_t s_wifi_event_group;
|
||||
|
||||
#define WIFI_ENABLED
|
||||
#include "wifi_sta.h"
|
||||
#endif
|
||||
|
||||
#ifdef WIFI_ENABLED
|
||||
#define WEB_SERVER_ENABLED
|
||||
#include "webserver.h"
|
||||
#endif
|
||||
|
||||
static const char *jannexTAG = "JANNEX";
|
||||
|
||||
void initJannex();
|
||||
void updateJannex();
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
void checkForUpdatesAndInstall(void *parameter);
|
||||
|
||||
extern bool updateAvailable;
|
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#define OTA_URL "https://" CONFIG_ESP_OTA_SERVER
|
||||
#define OTA_URL_PATH_getNewestVersion OTA_URL "/getVersion"
|
||||
#define OTA_URL_PATH_getBinary OTA_URL "/getFirmware"
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
void startOTAupdate();
|
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
|
||||
esp_err_t readStorage(const char *key, char *out_value, size_t *length, char *default_value);
|
||||
esp_err_t getBranch(char *out_value);
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "jannex/jannex.h"
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
|
||||
#define EXAMPLE_HTTP_QUERY_KEY_MAX_LEN (64)
|
||||
|
||||
void initServer();
|
||||
|
||||
#endif // WEB_SERVER_ENABLED
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "jannex/jannex.h"
|
||||
|
||||
#ifdef WIFI_ENABLED
|
||||
|
||||
void init_wifi();
|
||||
|
||||
#endif // WIFI_ENABLED
|
|
@ -1 +0,0 @@
|
|||
void checkForUpdatesAndInstall(void *parameter);
|
|
@ -0,0 +1,196 @@
|
|||
#include "jannex/api/console.h"
|
||||
#include "jannex/jannex.h"
|
||||
|
||||
#ifdef CONFIG_HTTP_SERVER_ENABLE_DEBUG_MODE
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
#include "esp_websocket_client.h"
|
||||
#include "esp_event.h"
|
||||
|
||||
char cacheMessage[CONFIG_HTTP_SERVER_DEBUG_CACHE_LENGTH];
|
||||
int cacheMessageIndex = 0;
|
||||
|
||||
const char *TAG = "Console";
|
||||
|
||||
esp_websocket_client_handle_t client = NULL;
|
||||
|
||||
void sendOlderMessages()
|
||||
{
|
||||
if (esp_websocket_client_is_connected(client))
|
||||
{
|
||||
if (cacheMessageIndex > 0)
|
||||
{
|
||||
esp_websocket_client_send_text(client, cacheMessage, cacheMessageIndex, 1000 / portTICK_PERIOD_MS);
|
||||
cacheMessageIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int jannex_LOG(const char *format, va_list args)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
// sprintf to jannex_LOG func and dynamically allocate memory
|
||||
char *message;
|
||||
status = vasprintf(&message, format, args);
|
||||
|
||||
// check if socket is online
|
||||
if (client != NULL && esp_websocket_client_is_connected(client))
|
||||
{
|
||||
sendOlderMessages();
|
||||
esp_websocket_client_send_text(client, message, strlen(message), 1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cacheMessageIndex + strlen(message) + 1 > CONFIG_HTTP_SERVER_DEBUG_CACHE_LENGTH)
|
||||
{
|
||||
// Cache is full
|
||||
// replace at the end of the cache
|
||||
|
||||
strcpy(cacheMessage + CONFIG_HTTP_SERVER_DEBUG_CACHE_LENGTH - 30, " ! CONSOLE CACHE OVERFLOW ! \n");
|
||||
cacheMessageIndex = CONFIG_HTTP_SERVER_DEBUG_CACHE_LENGTH;
|
||||
|
||||
goto END;
|
||||
}
|
||||
|
||||
// cache message
|
||||
if (cacheMessageIndex == 0)
|
||||
{
|
||||
strcpy(cacheMessage + cacheMessageIndex, message);
|
||||
cacheMessageIndex += strlen(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
// cacheMessage[cacheMessageIndex] = '\n';
|
||||
strcpy(cacheMessage + cacheMessageIndex, message);
|
||||
cacheMessageIndex += strlen(message);
|
||||
}
|
||||
}
|
||||
|
||||
END:
|
||||
|
||||
free(message);
|
||||
|
||||
if (status >= 0)
|
||||
{
|
||||
return vprintf(format, args); // print to console
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static void log_error_if_nonzero(const char *message, int error_code)
|
||||
{
|
||||
if (error_code != 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
static void websocket_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
|
||||
switch (event_id)
|
||||
{
|
||||
case WEBSOCKET_EVENT_CONNECTED:
|
||||
ESP_LOGI(TAG, "WEBSOCKET_EVENT_CONNECTED");
|
||||
sendOlderMessages();
|
||||
|
||||
ESP_LOGI(TAG, "Websocket connected! %s", CONFIG_HTTP_SERVER_DEBUG_URL);
|
||||
break;
|
||||
case WEBSOCKET_EVENT_DISCONNECTED:
|
||||
ESP_LOGE(TAG, "Websocket disconnected!");
|
||||
ESP_LOGI(TAG, "WEBSOCKET_EVENT_DISCONNECTED");
|
||||
log_error_if_nonzero("HTTP status code", data->error_handle.esp_ws_handshake_status_code);
|
||||
if (data->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT)
|
||||
{
|
||||
log_error_if_nonzero("reported from esp-tls", data->error_handle.esp_tls_last_esp_err);
|
||||
log_error_if_nonzero("reported from tls stack", data->error_handle.esp_tls_stack_err);
|
||||
log_error_if_nonzero("captured as transport's socket errno", data->error_handle.esp_transport_sock_errno);
|
||||
}
|
||||
break;
|
||||
case WEBSOCKET_EVENT_DATA:
|
||||
if (data->payload_len == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "WEBSOCKET_EVENT_DATA");
|
||||
ESP_LOGI(TAG, "Received opcode=%d", data->op_code);
|
||||
if (data->op_code == 0x08 && data->data_len == 2)
|
||||
{
|
||||
ESP_LOGW(TAG, "Received closed message with code=%d", 256 * data->data_ptr[0] + data->data_ptr[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "Received=%.*s", data->data_len, (char *)data->data_ptr);
|
||||
}
|
||||
|
||||
// If received data contains json structure it succeed to parse
|
||||
ESP_LOGW(TAG, "Total payload length=%d, data_len=%d, current payload offset=%d\r\n", data->payload_len, data->data_len, data->payload_offset);
|
||||
|
||||
break;
|
||||
case WEBSOCKET_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "WEBSOCKET_EVENT_ERROR");
|
||||
log_error_if_nonzero("HTTP status code", data->error_handle.esp_ws_handshake_status_code);
|
||||
if (data->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT)
|
||||
{
|
||||
log_error_if_nonzero("reported from esp-tls", data->error_handle.esp_tls_last_esp_err);
|
||||
log_error_if_nonzero("reported from tls stack", data->error_handle.esp_tls_stack_err);
|
||||
log_error_if_nonzero("captured as transport's socket errno", data->error_handle.esp_transport_sock_errno);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// function like printf and redirect the output to websocket
|
||||
|
||||
static void console_task(void *pvParameters)
|
||||
{
|
||||
esp_websocket_client_config_t websocket_cfg = {
|
||||
.uri = CONFIG_HTTP_SERVER_DEBUG_URL,
|
||||
.port = CONFIG_HTTP_SERVER_DEBUG_PORT,
|
||||
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "Connecting to %s... on port %d", websocket_cfg.uri, websocket_cfg.port);
|
||||
|
||||
client = esp_websocket_client_init(&websocket_cfg);
|
||||
esp_websocket_register_events(client, WEBSOCKET_EVENT_ANY, websocket_event_handler, (void *)client);
|
||||
|
||||
esp_websocket_client_start(client);
|
||||
|
||||
// just test here some data
|
||||
/*char data[32];
|
||||
int i = 0;
|
||||
while (true)
|
||||
{
|
||||
int len = sprintf(data, "hello %04d", i++);
|
||||
ESP_LOGI(TAG, "Sending %s", data);
|
||||
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
esp_websocket_client_destroy(client);*/
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void initConsole()
|
||||
{
|
||||
esp_log_set_vprintf(&jannex_LOG);
|
||||
}
|
||||
|
||||
void connectConsole()
|
||||
{
|
||||
// wait unitl wifi is connected
|
||||
// xEventGroupWaitBits(s_wifi_event_group, NETWORK_CONNECTED_BIT, false, true, portMAX_DELAY);
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
|
||||
xTaskCreate(console_task, "console_task", 4096, NULL, 5, NULL);
|
||||
}
|
||||
|
||||
#endif // CONFIG_HTTP_SERVER_ENABLE_DEBUG_MODE
|
|
@ -0,0 +1,12 @@
|
|||
#include "jannex/api/customAPIHandler.h"
|
||||
|
||||
#include <esp_http_server.h>
|
||||
|
||||
// Global instance of the custom API context
|
||||
CustomAPIHandler g_customAPIContext = NULL;
|
||||
|
||||
// Function to set the custom API handler
|
||||
void setCustomAPIHandler(CustomAPIHandler handler)
|
||||
{
|
||||
g_customAPIContext = handler;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
#include <stdio.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_http_client.h"
|
||||
|
||||
#include "esp_crt_bundle.h"
|
||||
|
||||
static const char *TAG = "httpsRequest";
|
||||
|
||||
esp_err_t https_get_request_SYNC(const char *url, char *out_buffer, int *out_buffer_length, int out_buffer_size, int *status_code)
|
||||
{
|
||||
int content_length = 0;
|
||||
|
||||
esp_http_client_config_t config = {
|
||||
.url = url,
|
||||
.event_handler = NULL,
|
||||
.transport_type = HTTP_TRANSPORT_OVER_SSL,
|
||||
.disable_auto_redirect = false,
|
||||
.crt_bundle_attach = esp_crt_bundle_attach,
|
||||
|
||||
};
|
||||
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
|
||||
// GET Request
|
||||
esp_http_client_set_method(client, HTTP_METHOD_GET);
|
||||
esp_err_t err = esp_http_client_open(client, 0);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
|
||||
}
|
||||
else
|
||||
{
|
||||
content_length = esp_http_client_fetch_headers(client);
|
||||
if (content_length < 0)
|
||||
{
|
||||
ESP_LOGE(TAG, "HTTP client fetch headers failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
int data_read = esp_http_client_read_response(client, out_buffer, out_buffer_size);
|
||||
out_buffer[data_read] = '\0';
|
||||
*out_buffer_length = data_read;
|
||||
if (data_read >= 0)
|
||||
{
|
||||
*status_code = esp_http_client_get_status_code(client);
|
||||
/*ESP_LOGI(TAG, "HTTP GET Status = %d, content_length = %lld",
|
||||
status_code,
|
||||
esp_http_client_get_content_length(client));*/
|
||||
|
||||
/*ESP_LOGI(TAG, "HTTP GET Response: %.*s", data_read, out_buffer);*/
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to read response");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_http_client_cleanup(client);
|
||||
return err;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "jannex/storage.h"
|
||||
|
||||
static const char *TAG = "initStorage";
|
||||
|
||||
void initStorage()
|
||||
{
|
||||
// Initialize NVS
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
|
||||
{
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
|
||||
void defaultValuesToStorage()
|
||||
{
|
||||
char branch[32];
|
||||
// readStorage("branch", default_branch, (size_t)32, GIT_DEFAULT_BRANCH);
|
||||
esp_err_t getBranch(char *branch);
|
||||
}
|
93
src/jannex.c
93
src/jannex.c
|
@ -1,20 +1,105 @@
|
|||
#include "jannex.h"
|
||||
#include "jannex/jannex.h"
|
||||
|
||||
#include "ota.h"
|
||||
#include "jannex/ota.h"
|
||||
#include "jannex/api/console.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "esp_log.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_event.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_netif.h"
|
||||
#include "esp_netif_sntp.h"
|
||||
#include "esp_sntp.h"
|
||||
|
||||
void time_sync_notification_cb(struct timeval *tv)
|
||||
{
|
||||
ESP_LOGI(jannexTAG, "Notification of a time synchronization event");
|
||||
}
|
||||
|
||||
void initialize_sntp()
|
||||
{
|
||||
ESP_LOGI(jannexTAG, "Initializing SNTP...");
|
||||
|
||||
// set timezone to berlin
|
||||
// setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);
|
||||
// tzset();
|
||||
|
||||
esp_sntp_config_t config = {
|
||||
.start = true,
|
||||
.sync_cb = time_sync_notification_cb,
|
||||
.smooth_sync = false,
|
||||
.server_from_dhcp = true, // accept NTP offers from DHCP server, if any (need to enable *before* connecting)
|
||||
.renew_servers_after_new_IP = true, // let esp-netif update configured SNTP server(s) after receiving DHCP lease
|
||||
.index_of_first_server = 1, // updates from server num 1, leaving server 0 (from DHCP) intact
|
||||
.num_of_servers = 1, // update only one server
|
||||
.servers = {CONFIG_NTP_SERVER}, // server pool
|
||||
|
||||
};
|
||||
|
||||
/*esp_netif_sntp_init(&config);
|
||||
|
||||
esp_netif_sntp_start();
|
||||
|
||||
// get current time in human readable format and print to log
|
||||
time_t now;
|
||||
struct tm timeinfo;
|
||||
time(&now);
|
||||
localtime_r(&now, &timeinfo);
|
||||
|
||||
if (!localtime(&timeinfo))
|
||||
{
|
||||
ESP_LOGE(jannexTAG, "Failed to obtain time");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(jannexTAG, "The current date/time in Berlin is: %s", asctime(&timeinfo));
|
||||
}*/
|
||||
}
|
||||
|
||||
void initJannex()
|
||||
{
|
||||
ESP_LOGI(jannexTAG, "LUL");
|
||||
initStorage();
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
#ifdef CONFIG_HTTP_SERVER_ENABLE_DEBUG_MODE
|
||||
initConsole();
|
||||
#endif // CONFIG_HTTP_SERVER_ENABLE_DEBUG_MODE
|
||||
|
||||
const esp_app_desc_t *app_desc = esp_app_get_description();
|
||||
|
||||
ESP_LOGI(jannexTAG, "Initializing Jannex");
|
||||
|
||||
ESP_LOGI(jannexTAG, "Current Build version: %s", app_desc->version);
|
||||
ESP_LOGI(jannexTAG, "Current Build name: %s", app_desc->project_name);
|
||||
ESP_LOGI(jannexTAG, "Current Build date: %s", app_desc->date);
|
||||
ESP_LOGI(jannexTAG, "Current Build time: %s", app_desc->time);
|
||||
|
||||
defaultValuesToStorage();
|
||||
|
||||
#ifdef WIFI_ENABLED
|
||||
esp_log_level_set("esp-x509-crt-bundle", ESP_LOG_WARN);
|
||||
esp_log_level_set("wifi", ESP_LOG_WARN);
|
||||
init_wifi();
|
||||
#endif
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
initServer();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HTTP_SERVER_ENABLE_DEBUG_MODE
|
||||
connectConsole();
|
||||
#endif // CONFIG_HTTP_SERVER_ENABLE_DEBUG_MODE
|
||||
|
||||
initialize_sntp();
|
||||
}
|
||||
|
||||
void updateJannex()
|
||||
{
|
||||
xTaskCreate(&checkForUpdatesAndInstall, "checkForUpdatesAndInstall", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
|
||||
xTaskCreate(&checkForUpdatesAndInstall, "checkForUpdatesAndInstall", 8192, NULL, 5, NULL);
|
||||
}
|
155
src/ota.c
155
src/ota.c
|
@ -1,10 +1,161 @@
|
|||
#include "jannex.h"
|
||||
#include "jannex/jannex.h"
|
||||
|
||||
#include "jannex/otaAPI.h"
|
||||
#include "jannex/otaUpdate.h"
|
||||
|
||||
#include "jannex/httpsRequest.h"
|
||||
#include "json_parser.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
|
||||
#include "esp_mac.h"
|
||||
|
||||
#include "esp_app_desc.h"
|
||||
#include "esp_ota_ops.h"
|
||||
|
||||
bool updateAvailable = false;
|
||||
bool isCheckingForUpdates = false;
|
||||
|
||||
void getNewestVersion()
|
||||
{
|
||||
isCheckingForUpdates = true;
|
||||
|
||||
// buffer for the response
|
||||
size_t length = 256;
|
||||
|
||||
char response[length];
|
||||
int status_code = 0;
|
||||
int responseLength = 0;
|
||||
|
||||
// get mac address
|
||||
uint8_t mac[6];
|
||||
esp_efuse_mac_get_default(mac);
|
||||
|
||||
// get current version
|
||||
const esp_app_desc_t *app_desc = esp_app_get_description();
|
||||
char *currentVersion = app_desc->version;
|
||||
|
||||
char branch[32];
|
||||
getBranch(branch);
|
||||
|
||||
char url[256];
|
||||
sprintf(url, "%s?mac=%02X:%02X:%02X:%02X:%02X:%02X&device=%s&branch=%s", OTA_URL_PATH_getNewestVersion, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], app_desc->project_name, branch);
|
||||
|
||||
// make the request
|
||||
esp_err_t err = https_get_request_SYNC(url, response, &responseLength, length, &status_code);
|
||||
|
||||
// ESP_LOGI(jannexTAG, "HTTP GET Response: %i %i %s", status_code, responseLength, response);
|
||||
|
||||
jparse_ctx_t jctx;
|
||||
int ret = json_parse_start(&jctx, response, responseLength);
|
||||
if (ret != OS_SUCCESS)
|
||||
{
|
||||
ESP_LOGE(jannexTAG, "HTTP GET Response: %i %i %s", status_code, responseLength, response);
|
||||
ESP_LOGE(jannexTAG, "Parser failed");
|
||||
isCheckingForUpdates = false;
|
||||
return;
|
||||
}
|
||||
char newestVersion[32];
|
||||
|
||||
if (json_obj_get_string(&jctx, "error", newestVersion, sizeof(newestVersion)) == OS_SUCCESS)
|
||||
{
|
||||
ESP_LOGW(jannexTAG, "Error: %s", newestVersion);
|
||||
// ERROR
|
||||
isCheckingForUpdates = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (json_obj_get_string(&jctx, "version", newestVersion, sizeof(newestVersion)) == OS_SUCCESS)
|
||||
{
|
||||
// ESP_LOGI(jannexTAG, "newestVersion %s", newestVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(jannexTAG, "No version");
|
||||
isCheckingForUpdates = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// print current version
|
||||
// ESP_LOGI(jannexTAG, "Current version: %s", currentVersion);
|
||||
|
||||
// newestVersion and currentVersion are strings with the format two numbers separated by a dot (e.g. 1.2) now we need to compare them
|
||||
// first we need to split the strings into two numbers
|
||||
char newestVersionMajor[16];
|
||||
char newestVersionMinor[16];
|
||||
char currentVersionMajor[16];
|
||||
char currentVersionMinor[16];
|
||||
|
||||
// split newestVersion
|
||||
int i = 0;
|
||||
while (newestVersion[i] != '.')
|
||||
{
|
||||
newestVersionMajor[i] = newestVersion[i];
|
||||
i++;
|
||||
}
|
||||
newestVersionMajor[i] = '\0';
|
||||
i++;
|
||||
int j = 0;
|
||||
while (newestVersion[i] != '\0')
|
||||
{
|
||||
newestVersionMinor[j] = newestVersion[i];
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
newestVersionMinor[j] = '\0';
|
||||
|
||||
// split currentVersion
|
||||
i = 0;
|
||||
while (currentVersion[i] != '.')
|
||||
{
|
||||
currentVersionMajor[i] = currentVersion[i];
|
||||
i++;
|
||||
}
|
||||
currentVersionMajor[i] = '\0';
|
||||
i++;
|
||||
j = 0;
|
||||
while (currentVersion[i] != '\0')
|
||||
{
|
||||
currentVersionMinor[j] = currentVersion[i];
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
currentVersionMinor[j] = '\0';
|
||||
|
||||
// compare the numbers
|
||||
int newestVersionMajorInt = atoi(newestVersionMajor);
|
||||
int newestVersionMinorInt = atoi(newestVersionMinor);
|
||||
int currentVersionMajorInt = atoi(currentVersionMajor);
|
||||
int currentVersionMinorInt = atoi(currentVersionMinor);
|
||||
|
||||
if (newestVersionMajorInt != currentVersionMajorInt) // or only for new version: newestVersionMajorInt > currentVersionMajorInt
|
||||
{
|
||||
// major update
|
||||
ESP_LOGI(jannexTAG, "Major update available");
|
||||
updateAvailable = true;
|
||||
}
|
||||
else if (newestVersionMinorInt != currentVersionMinorInt) // or only for new version: newestVersionMinorInt > currentVersionMinorInt
|
||||
{
|
||||
ESP_LOGI(jannexTAG, "Minor update available");
|
||||
updateAvailable = true;
|
||||
}
|
||||
|
||||
isCheckingForUpdates = false;
|
||||
|
||||
// esp ota do update
|
||||
if (updateAvailable)
|
||||
{
|
||||
|
||||
startOTAupdate();
|
||||
}
|
||||
}
|
||||
|
||||
void checkForUpdatesAndInstall(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
printf("Task is running\n");
|
||||
if (isCheckingForUpdates == false)
|
||||
getNewestVersion();
|
||||
|
||||
#ifdef CONFIG_FIRMWARE_UPDATE_SCAN_SECONDS
|
||||
if (CONFIG_FIRMWARE_UPDATE_SCAN_SECONDS >= 1)
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
#include "jannex/jannex.h"
|
||||
|
||||
#include "jannex/ota.h"
|
||||
#include "jannex/otaAPI.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#include "esp_mac.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "esp_http_client.h"
|
||||
#include "esp_crt_bundle.h"
|
||||
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_https_ota.h"
|
||||
|
||||
static const char *TAG = "otaUpgrade";
|
||||
|
||||
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
|
||||
{
|
||||
switch (evt->event_id)
|
||||
{
|
||||
case HTTP_EVENT_ERROR:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_ERROR");
|
||||
break;
|
||||
case HTTP_EVENT_ON_CONNECTED:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
|
||||
break;
|
||||
case HTTP_EVENT_HEADER_SENT:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
|
||||
break;
|
||||
case HTTP_EVENT_ON_HEADER:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
|
||||
break;
|
||||
case HTTP_EVENT_ON_DATA:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
|
||||
break;
|
||||
case HTTP_EVENT_ON_FINISH:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
|
||||
break;
|
||||
case HTTP_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
|
||||
break;
|
||||
case HTTP_EVENT_REDIRECT:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_REDIRECT");
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void startOTAupdate()
|
||||
{
|
||||
// get mac address
|
||||
uint8_t mac[6];
|
||||
esp_efuse_mac_get_default(mac);
|
||||
|
||||
// needed to get project name
|
||||
const esp_app_desc_t *app_desc = esp_app_get_description();
|
||||
|
||||
char branch[32];
|
||||
getBranch(branch);
|
||||
|
||||
char url[256];
|
||||
sprintf(url, "%s?mac=%02X:%02X:%02X:%02X:%02X:%02X&device=%s&branch=%s", OTA_URL_PATH_getBinary, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], app_desc->project_name, branch);
|
||||
|
||||
esp_http_client_config_t config = {
|
||||
.url = url,
|
||||
.crt_bundle_attach = esp_crt_bundle_attach,
|
||||
.buffer_size = 4096,
|
||||
|
||||
.event_handler = _http_event_handler,
|
||||
.keep_alive_enable = true,
|
||||
#ifdef CONFIG_EXAMPLE_FIRMWARE_UPGRADE_BIND_IF // possible to bind to specific interface
|
||||
.if_name = &ifr,
|
||||
#endif
|
||||
};
|
||||
|
||||
esp_https_ota_config_t ota_config = {
|
||||
.http_config = &config,
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "Starting OTA update");
|
||||
ESP_LOGI(TAG, "Attempting to download update from %s", config.url);
|
||||
esp_err_t err = esp_https_ota(&ota_config);
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "OTA Succeed, Rebooting...");
|
||||
esp_restart();
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "Firmware upgrade failed!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
static const char *TAG = "Storage";
|
||||
|
||||
#ifndef GIT_DEFAULT_BRANCH
|
||||
#define GIT_DEFAULT_BRANCH "unknown"
|
||||
#endif
|
||||
|
||||
esp_err_t readStorage(const char *key, char *out_value, size_t *length, char *default_value)
|
||||
{
|
||||
|
||||
// read nvs for key
|
||||
nvs_handle_t my_handle;
|
||||
esp_err_t ret = nvs_open("storage", NVS_READONLY, &my_handle);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = nvs_get_str(my_handle, key, &out_value[0], &length);
|
||||
switch (ret)
|
||||
{
|
||||
case ESP_OK:
|
||||
// ESP_LOGI(TAG, "Current %s: %s", key, out_value);
|
||||
|
||||
return ret;
|
||||
case ESP_ERR_NVS_NOT_FOUND:
|
||||
ESP_LOGI(TAG, "The value is not initialized yet!\n");
|
||||
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Error (%s) reading!\n", esp_err_to_name(ret));
|
||||
}
|
||||
nvs_close(my_handle);
|
||||
}
|
||||
|
||||
// if not found, set to default value
|
||||
ret = nvs_open("storage", NVS_READWRITE, &my_handle);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(ret));
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = nvs_set_str(my_handle, key, default_value);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ret = nvs_get_str(my_handle, key, &out_value[0], &length);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
ESP_LOGI(TAG, "Current %s: %s", key, out_value);
|
||||
nvs_close(my_handle);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t getBranch(char *out_value)
|
||||
{
|
||||
size_t length = 32;
|
||||
char default_value[32];
|
||||
esp_err_t ret = readStorage("branch", out_value, &length, GIT_DEFAULT_BRANCH);
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
#include "jannex/webserver.h"
|
||||
|
||||
#ifdef WEB_SERVER_ENABLED
|
||||
|
||||
#include "jannex/api/customAPIHandler.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_netif.h"
|
||||
#include <esp_http_server.h>
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
static const char *TAG = "http server";
|
||||
|
||||
static esp_err_t hello_get_handler(httpd_req_t *req)
|
||||
{
|
||||
char *buf;
|
||||
size_t buf_len;
|
||||
|
||||
/* Get header value string length and allocate memory for length + 1,
|
||||
* extra byte for null termination */
|
||||
buf_len = httpd_req_get_hdr_value_len(req, "Host") + 1;
|
||||
if (buf_len > 1)
|
||||
{
|
||||
buf = malloc(buf_len);
|
||||
/* Copy null terminated value string into buffer */
|
||||
if (httpd_req_get_hdr_value_str(req, "Host", buf, buf_len) == ESP_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "Found header => Host: %s", buf);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-2") + 1;
|
||||
if (buf_len > 1)
|
||||
{
|
||||
buf = malloc(buf_len);
|
||||
if (httpd_req_get_hdr_value_str(req, "Test-Header-2", buf, buf_len) == ESP_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "Found header => Test-Header-2: %s", buf);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
buf_len = httpd_req_get_hdr_value_len(req, "Test-Header-1") + 1;
|
||||
if (buf_len > 1)
|
||||
{
|
||||
buf = malloc(buf_len);
|
||||
if (httpd_req_get_hdr_value_str(req, "Test-Header-1", buf, buf_len) == ESP_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "Found header => Test-Header-1: %s", buf);
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/* Read URL query string length and allocate memory for length + 1,
|
||||
* extra byte for null termination */
|
||||
buf_len = httpd_req_get_url_query_len(req) + 1;
|
||||
if (buf_len > 1)
|
||||
{
|
||||
buf = malloc(buf_len);
|
||||
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "Found URL query => %s", buf);
|
||||
char param[EXAMPLE_HTTP_QUERY_KEY_MAX_LEN], dec_param[EXAMPLE_HTTP_QUERY_KEY_MAX_LEN] = {0};
|
||||
/* Get value of expected key from query string */
|
||||
if (httpd_query_key_value(buf, "start", param, sizeof(param)) == ESP_OK)
|
||||
{
|
||||
ESP_LOGI(TAG, "Found URL query parameter => query1=%s", param);
|
||||
// example_uri_decode(dec_param, param, strnlen(param, EXAMPLE_HTTP_QUERY_KEY_MAX_LEN));
|
||||
ESP_LOGI(TAG, "Decoded query parameter => %s", param);
|
||||
}
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
/* Set some custom headers */
|
||||
httpd_resp_set_hdr(req, "Custom-Header-1", "Custom-Value-1");
|
||||
httpd_resp_set_hdr(req, "Custom-Header-2", "Custom-Value-2");
|
||||
|
||||
/* Send response with custom headers and body set as the
|
||||
* string passed in user context*/
|
||||
const char *resp_str = (const char *)req->user_ctx;
|
||||
httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
|
||||
|
||||
/* After sending the HTTP response the old HTTP request
|
||||
* headers are lost. Check if HTTP request headers can be read now. */
|
||||
if (httpd_req_get_hdr_value_len(req, "Host") == 0)
|
||||
{
|
||||
ESP_LOGI(TAG, "Request headers lost");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static const httpd_uri_t hello = {
|
||||
.uri = "/hello",
|
||||
.method = HTTP_GET,
|
||||
.handler = hello_get_handler,
|
||||
/* Let's pass response string in user
|
||||
* context to demonstrate it's usage */
|
||||
.user_ctx = "Hello World!"};
|
||||
|
||||
static httpd_handle_t start_webserver(void)
|
||||
{
|
||||
httpd_handle_t server = NULL;
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
config.lru_purge_enable = true;
|
||||
|
||||
// Start the httpd server
|
||||
ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
|
||||
if (httpd_start(&server, &config) == ESP_OK)
|
||||
{
|
||||
// Set URI handlers
|
||||
ESP_LOGI(TAG, "Registering URI handlers");
|
||||
httpd_register_uri_handler(server, &hello);
|
||||
|
||||
ESP_LOGI(TAG, "Registering custom URI handlers..");
|
||||
|
||||
// check if g_customAPIContext is defined
|
||||
if (g_customAPIContext != NULL)
|
||||
{
|
||||
g_customAPIContext(server);
|
||||
ESP_LOGI(TAG, "Registered custom URI handlers!");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "No custom URI handlers registered!");
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Error starting server!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void initServer()
|
||||
{
|
||||
|
||||
static httpd_handle_t server = NULL;
|
||||
server = start_webserver();
|
||||
|
||||
if (server == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "Error starting server!");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // WEB_SERVER_ENABLED
|
|
@ -0,0 +1,128 @@
|
|||
#include "jannex/wifi_sta.h"
|
||||
|
||||
#ifdef WIFI_ENABLED
|
||||
|
||||
#include "jannex/jannex.h"
|
||||
|
||||
#include "jannex/webserver.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_netif.h"
|
||||
#include "esp_log.h"
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_system.h>
|
||||
|
||||
#include <esp_http_server.h>
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sys.h"
|
||||
|
||||
static const char *TAG = "wifi station";
|
||||
|
||||
static int s_retry_num = 0;
|
||||
|
||||
static void event_handler(void *arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START)
|
||||
{
|
||||
esp_wifi_connect();
|
||||
}
|
||||
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED)
|
||||
{
|
||||
// if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY)
|
||||
// {
|
||||
esp_wifi_connect();
|
||||
s_retry_num++;
|
||||
ESP_LOGI(TAG, "retry to connect to the AP");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// xEventGroupSetBits(s_wifi_event_group, NETWORK_FAIL_BIT);
|
||||
// }
|
||||
// ESP_LOGI(TAG, "connect to the AP fail");
|
||||
}
|
||||
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP)
|
||||
{
|
||||
ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data;
|
||||
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
|
||||
s_retry_num = 0;
|
||||
xEventGroupSetBits(s_wifi_event_group, NETWORK_CONNECTED_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
void init_wifi()
|
||||
{
|
||||
s_wifi_event_group = xEventGroupCreate();
|
||||
|
||||
esp_netif_create_default_wifi_sta();
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
esp_event_handler_instance_t instance_any_id;
|
||||
esp_event_handler_instance_t instance_got_ip;
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
|
||||
ESP_EVENT_ANY_ID,
|
||||
&event_handler,
|
||||
NULL,
|
||||
&instance_any_id));
|
||||
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
|
||||
IP_EVENT_STA_GOT_IP,
|
||||
&event_handler,
|
||||
NULL,
|
||||
&instance_got_ip));
|
||||
|
||||
wifi_config_t wifi_config = {
|
||||
.sta = {
|
||||
.ssid = CONFIG_ESP_WIFI_SSID,
|
||||
.password = CONFIG_ESP_WIFI_PASSWORD,
|
||||
/* Authmode threshold resets to WPA2 as default if password matches WPA2 standards (pasword len => 8).
|
||||
* If you want to connect the device to deprecated WEP/WPA networks, Please set the threshold value
|
||||
* to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with length and format matching to
|
||||
* WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK standards.
|
||||
*/
|
||||
//.threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD,
|
||||
//.sae_pwe_h2e = ESP_WIFI_SAE_MODE,
|
||||
//.sae_h2e_identifier = EXAMPLE_H2E_IDENTIFIER,
|
||||
},
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
|
||||
ESP_LOGI(TAG, "wifi_init_sta finished.");
|
||||
|
||||
/* Waiting until either the connection is established (NETWORK_CONNECTED_BIT) or connection failed for the maximum
|
||||
* number of re-tries (NETWORK_FAIL_BIT). The bits are set by event_handler() (see above) */
|
||||
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
||||
NETWORK_CONNECTED_BIT | NETWORK_FAIL_BIT,
|
||||
pdFALSE,
|
||||
pdFALSE,
|
||||
portMAX_DELAY);
|
||||
|
||||
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
|
||||
* happened. */
|
||||
if (bits & NETWORK_CONNECTED_BIT)
|
||||
{
|
||||
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
|
||||
CONFIG_ESP_WIFI_SSID, "********");
|
||||
}
|
||||
else if (bits & NETWORK_FAIL_BIT)
|
||||
{
|
||||
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s",
|
||||
CONFIG_ESP_WIFI_PASSWORD, "********");
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "UNEXPECTED EVENT");
|
||||
}
|
||||
}
|
||||
|
||||
#endif // WIFI_ENABLED
|
Loading…
Reference in New Issue