kopia lustrzana https://github.com/martin-ger/esp_mqtt
912 wiersze
24 KiB
C
912 wiersze
24 KiB
C
#include "c_types.h"
|
|
#include "mem.h"
|
|
#include "ets_sys.h"
|
|
#include "osapi.h"
|
|
#include "os_type.h"
|
|
#include "sys_time.h"
|
|
|
|
#include "string.h"
|
|
#include "driver/uart.h"
|
|
|
|
#include "global.h"
|
|
|
|
#ifdef GPIO
|
|
//#include "easygpio.h"
|
|
#include "pwm.h"
|
|
#define PWM_CHANNELS 5
|
|
const uint32_t period = 5000; // * 200ns ^= 1 kHz
|
|
#endif
|
|
|
|
#ifdef NTP
|
|
#include "ntp.h"
|
|
uint64_t t_ntp_resync = 0;
|
|
#endif
|
|
|
|
#ifdef MDNS
|
|
static struct mdns_info mdnsinfo;
|
|
#endif
|
|
|
|
#ifdef SCRIPTED
|
|
#include "lang.h"
|
|
#include "pub_list.h"
|
|
|
|
struct espconn *downloadCon;
|
|
struct espconn *scriptcon;
|
|
uint8_t *load_script;
|
|
uint32_t load_size;
|
|
#endif
|
|
|
|
/* System Task, for signals refer to user_config.h */
|
|
#define user_procTaskPrio 0
|
|
#define user_procTaskQueueLen 2
|
|
os_event_t user_procTaskQueue[user_procTaskQueueLen];
|
|
static void user_procTask(os_event_t * events);
|
|
|
|
static os_timer_t ptimer;
|
|
|
|
static int system_output;
|
|
|
|
/* Some stats */
|
|
uint64_t t_old;
|
|
|
|
/* Hold the system wide configuration */
|
|
sysconfig_t config;
|
|
|
|
ringbuf_t console_rx_buffer, console_tx_buffer;
|
|
|
|
ip_addr_t my_ip;
|
|
ip_addr_t dns_ip;
|
|
bool connected;
|
|
uint8_t my_channel;
|
|
bool do_ip_config;
|
|
|
|
void ICACHE_FLASH_ATTR user_set_softap_wifi_config(void);
|
|
void ICACHE_FLASH_ATTR user_set_softap_ip_config(void);
|
|
|
|
uint8_t remote_console_disconnect;
|
|
struct espconn *console_conn;
|
|
bool client_sent_pending;
|
|
|
|
LOCAL ICACHE_FLASH_ATTR void void_write_char(char c) {}
|
|
|
|
void ICACHE_FLASH_ATTR to_console(char *str) {
|
|
ringbuf_memcpy_into(console_tx_buffer, str, os_strlen(str));
|
|
}
|
|
|
|
bool ICACHE_FLASH_ATTR check_connection_access(struct espconn *pesp_conn, uint8_t access_flags) {
|
|
remot_info *premot = NULL;
|
|
ip_addr_t *remote_addr;
|
|
bool is_local;
|
|
|
|
remote_addr = (ip_addr_t *)&(pesp_conn->proto.tcp->remote_ip);
|
|
//os_printf("Remote addr is %d.%d.%d.%d\r\n", IP2STR(remote_addr));
|
|
is_local = (remote_addr->addr & 0x00ffffff) == (config.network_addr.addr & 0x00ffffff);
|
|
|
|
if (is_local && (access_flags & LOCAL_ACCESS))
|
|
return true;
|
|
if (!is_local && (access_flags & REMOTE_ACCESS))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
#ifdef MQTT_CLIENT
|
|
MQTT_Client mqttClient;
|
|
bool mqtt_enabled, mqtt_connected;
|
|
|
|
static void ICACHE_FLASH_ATTR mqttConnectedCb(uint32_t * args) {
|
|
uint8_t ip_str[16];
|
|
|
|
MQTT_Client *client = (MQTT_Client *) args;
|
|
mqtt_connected = true;
|
|
#ifdef SCRIPTED
|
|
interpreter_mqtt_connect();
|
|
#endif
|
|
os_printf("MQTT client connected\r\n");
|
|
}
|
|
|
|
static void ICACHE_FLASH_ATTR mqttDisconnectedCb(uint32_t * args) {
|
|
MQTT_Client *client = (MQTT_Client *) args;
|
|
mqtt_connected = false;
|
|
os_printf("MQTT client disconnected\r\n");
|
|
}
|
|
|
|
static void ICACHE_FLASH_ATTR mqttPublishedCb(uint32_t * args) {
|
|
MQTT_Client *client = (MQTT_Client *) args;
|
|
// os_printf("MQTT: Published\r\n");
|
|
}
|
|
|
|
static void ICACHE_FLASH_ATTR mqttDataCb(uint32_t * args, const char *topic,
|
|
uint32_t topic_len, const char *data, uint32_t data_len) {
|
|
#ifdef SCRIPTED
|
|
MQTT_Client *client = (MQTT_Client *) args;
|
|
|
|
char *topic_copy = (char*)os_malloc(topic_len+1);
|
|
if (topic_copy == NULL)
|
|
return;
|
|
os_memcpy(topic_copy, topic, topic_len);
|
|
topic_copy[topic_len] = '\0';
|
|
|
|
interpreter_topic_received(topic_copy, data, data_len, false);
|
|
|
|
os_free(topic_copy);
|
|
|
|
// Any local topics to process as result?
|
|
pub_process();
|
|
|
|
#endif
|
|
}
|
|
#endif /* MQTT_CLIENT */
|
|
|
|
#ifdef SCRIPTED
|
|
static void ICACHE_FLASH_ATTR script_recv_cb(void *arg, char *data, unsigned short length) {
|
|
struct espconn *pespconn = (struct espconn *)arg;
|
|
int index;
|
|
uint8_t ch;
|
|
|
|
for (index = 0; index < length; index++) {
|
|
ch = *(data + index);
|
|
//os_printf("%c", ch);
|
|
if (load_size < MAX_SCRIPT_SIZE - 5)
|
|
load_script[4 + load_size++] = ch;
|
|
}
|
|
}
|
|
|
|
void ICACHE_FLASH_ATTR http_script_cb(char *response_body, int http_status, char *response_headers, int body_size) {
|
|
char response[64];
|
|
|
|
if (http_status != 200) {
|
|
os_sprintf(response, "\rHTTP script upload failed (error code %d)\r\n", http_status);
|
|
to_console(response);
|
|
return;
|
|
}
|
|
|
|
if (body_size > MAX_SCRIPT_SIZE-5) {
|
|
os_sprintf(response, "\rHTTP script upload failed (script too long)\r\n");
|
|
to_console(response);
|
|
return;
|
|
}
|
|
|
|
char *load_script = (char *)os_malloc(body_size+5);
|
|
if (load_script == NULL) {
|
|
os_sprintf(response, "\rHTTP script upload failed (out of memory)\r\n");
|
|
to_console(response);
|
|
return;
|
|
}
|
|
//os_printf("LOAD: %d %x::%s\r\n", body_size, load_script, response_body);
|
|
os_memcpy(&load_script[4], response_body, body_size);
|
|
load_script[4 + body_size] = '\0';
|
|
*(uint32_t *) load_script = body_size + 5;
|
|
blob_save(SCRIPT_SLOT, (uint32_t *) load_script, body_size + 5);;
|
|
os_free(load_script);
|
|
blob_zero(VARS_SLOT, MAX_FLASH_SLOTS * FLASH_SLOT_LEN);
|
|
|
|
os_sprintf(response, "\rHTTP script download completed (%d Bytes)\r\n", body_size);
|
|
to_console(response);
|
|
|
|
system_os_post(user_procTaskPrio, SIG_SCRIPT_HTTP_LOADED, (ETSParam) scriptcon);
|
|
}
|
|
|
|
static void ICACHE_FLASH_ATTR script_discon_cb(void *arg) {
|
|
char response[64];
|
|
|
|
load_script[4 + load_size] = '\0';
|
|
*(uint32_t *) load_script = load_size + 5;
|
|
blob_save(SCRIPT_SLOT, (uint32_t *) load_script, load_size + 5);
|
|
os_free(load_script);
|
|
blob_zero(VARS_SLOT, MAX_FLASH_SLOTS * FLASH_SLOT_LEN);
|
|
|
|
os_sprintf(response, "\rScript upload completed (%d Bytes)\r\n", load_size);
|
|
to_console(response);
|
|
|
|
system_os_post(user_procTaskPrio, SIG_SCRIPT_LOADED, (ETSParam) scriptcon);
|
|
}
|
|
|
|
/* Called when a client connects to the script server */
|
|
void ICACHE_FLASH_ATTR script_connected_cb(void *arg) {
|
|
char response[64];
|
|
struct espconn *pespconn = (struct espconn *)arg;
|
|
|
|
load_script = (uint8_t *) os_malloc(MAX_SCRIPT_SIZE);
|
|
load_size = 0;
|
|
|
|
//espconn_regist_sentcb(pespconn, tcp_client_sent_cb);
|
|
espconn_regist_disconcb(pespconn, script_discon_cb);
|
|
espconn_regist_recvcb(pespconn, script_recv_cb);
|
|
espconn_regist_time(pespconn, 300, 1);
|
|
}
|
|
|
|
uint32_t ICACHE_FLASH_ATTR get_script_size(void) {
|
|
uint32_t size;
|
|
|
|
blob_load(SCRIPT_SLOT, &size, 4);
|
|
return size;
|
|
}
|
|
|
|
uint8_t *my_script = NULL;
|
|
uint32_t ICACHE_FLASH_ATTR read_script(void) {
|
|
uint32_t size = get_script_size();
|
|
if (size <= 5)
|
|
return 0;
|
|
|
|
my_script = (uint8_t *) os_malloc(size);
|
|
|
|
if (my_script == 0) {
|
|
os_printf("Out of memory");
|
|
return 0;
|
|
}
|
|
|
|
blob_load(SCRIPT_SLOT, (uint32_t *) my_script, size);
|
|
|
|
uint32_t num_token = text_into_tokens(my_script + 4);
|
|
|
|
if (num_token == 0) {
|
|
os_free(my_script);
|
|
my_script = NULL;
|
|
}
|
|
return num_token;
|
|
}
|
|
|
|
void ICACHE_FLASH_ATTR free_script(void) {
|
|
if (my_script != NULL) {
|
|
free_tokens();
|
|
os_free(my_script);
|
|
}
|
|
my_script = NULL;
|
|
}
|
|
#endif /* SCRIPTED */
|
|
|
|
void ICACHE_FLASH_ATTR console_send_response(struct espconn *pespconn, bool serial_force) {
|
|
uint16_t len = ringbuf_bytes_used(console_tx_buffer);
|
|
char payload[len];
|
|
|
|
if (len == 0)
|
|
return;
|
|
|
|
ringbuf_memcpy_from(payload, console_tx_buffer, len);
|
|
if (pespconn != NULL) {
|
|
if (!client_sent_pending) {
|
|
espconn_sent(pespconn, payload, len);
|
|
client_sent_pending = true;
|
|
}
|
|
} else {
|
|
if (system_output >= SYSTEM_OUTPUT_CMD || serial_force) {
|
|
UART_Send(0, payload, len);
|
|
}
|
|
#ifdef BACKLOG
|
|
if (backlog_buffer != NULL) {
|
|
char outbuf[10];
|
|
if (ringbuf_bytes_free(backlog_buffer) < len && !ringbuf_is_empty(backlog_buffer)) {
|
|
ringbuf_memcpy_from(outbuf, backlog_buffer, sizeof(outbuf));
|
|
}
|
|
ringbuf_memcpy_into(backlog_buffer, payload, len);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void ICACHE_FLASH_ATTR con_print(uint8_t *str) {
|
|
ringbuf_memcpy_into(console_tx_buffer, str, os_strlen(str));
|
|
system_os_post(user_procTaskPrio, SIG_CONSOLE_TX_RAW, (ETSParam) console_conn);
|
|
}
|
|
|
|
void ICACHE_FLASH_ATTR serial_out(uint8_t *str) {
|
|
ringbuf_memcpy_into(console_tx_buffer, str, os_strlen(str));
|
|
system_os_post(user_procTaskPrio, SIG_SERIAL_TX, (ETSParam) NULL);
|
|
}
|
|
|
|
bool ICACHE_FLASH_ATTR delete_retainedtopics() {
|
|
clear_retainedtopics();
|
|
blob_zero(RETAINED_SLOT, MAX_RETAINED_LEN);
|
|
}
|
|
|
|
bool ICACHE_FLASH_ATTR save_retainedtopics() {
|
|
uint8_t buffer[MAX_RETAINED_LEN];
|
|
int len = sizeof(buffer);
|
|
len = serialize_retainedtopics(buffer, len);
|
|
|
|
if (len) {
|
|
blob_save(RETAINED_SLOT, (uint32_t *)buffer, len);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ICACHE_FLASH_ATTR load_retainedtopics() {
|
|
uint8_t buffer[MAX_RETAINED_LEN];
|
|
int len = sizeof(buffer);
|
|
|
|
blob_load(RETAINED_SLOT, (uint32_t *)buffer, len);
|
|
return deserialize_retainedtopics(buffer, len);
|
|
}
|
|
|
|
void MQTT_local_DataCallback(uint32_t * args, const char *topic, uint32_t topic_len, const char *data, uint32_t length) {
|
|
//os_printf("Received: \"%s\" len: %d\r\n", topic, length);
|
|
#ifdef SCRIPTED
|
|
//interpreter_topic_received(topic, data, length, true);
|
|
pub_insert(topic, topic_len, data, length, true);
|
|
system_os_post(user_procTaskPrio, SIG_TOPIC_RECEIVED, 0);
|
|
#endif
|
|
}
|
|
|
|
#ifdef SCRIPTED
|
|
void ICACHE_FLASH_ATTR do_command(char *t1, char *t2, char *t3) {
|
|
ringbuf_memcpy_into(console_rx_buffer, t1, os_strlen(t1));
|
|
ringbuf_memcpy_into(console_rx_buffer, " ", 1);
|
|
ringbuf_memcpy_into(console_rx_buffer, t2, os_strlen(t2));
|
|
ringbuf_memcpy_into(console_rx_buffer, " ", 1);
|
|
ringbuf_memcpy_into(console_rx_buffer, t3, os_strlen(t3));
|
|
|
|
uint8_t save_locked = config.locked;
|
|
config.locked = false;
|
|
console_handle_command(console_conn);
|
|
config.locked = save_locked;
|
|
|
|
system_os_post(user_procTaskPrio, SIG_CONSOLE_TX_RAW, (ETSParam) console_conn);
|
|
}
|
|
#endif
|
|
|
|
#ifdef REMOTE_CONFIG
|
|
static void ICACHE_FLASH_ATTR tcp_client_recv_cb(void *arg, char *data, unsigned short length) {
|
|
struct espconn *pespconn = (struct espconn *)arg;
|
|
int index;
|
|
uint8_t ch;
|
|
|
|
for (index = 0; index < length; index++) {
|
|
ch = *(data + index);
|
|
ringbuf_memcpy_into(console_rx_buffer, &ch, 1);
|
|
|
|
// If a complete commandline is received, then signal the main
|
|
// task that command is available for processing
|
|
if (ch == '\n')
|
|
system_os_post(user_procTaskPrio, SIG_CONSOLE_RX, (ETSParam) arg);
|
|
}
|
|
|
|
*(data + length) = 0;
|
|
}
|
|
|
|
static void ICACHE_FLASH_ATTR tcp_client_sent_cb(void *arg) {
|
|
struct espconn *pespconn = (struct espconn *)arg;
|
|
|
|
client_sent_pending = false;
|
|
console_send_response(pespconn, false);
|
|
|
|
}
|
|
|
|
static void ICACHE_FLASH_ATTR tcp_client_discon_cb(void *arg) {
|
|
os_printf("tcp_client_discon_cb(): client disconnected\n");
|
|
struct espconn *pespconn = (struct espconn *)arg;
|
|
console_conn = NULL;
|
|
}
|
|
|
|
/* Called when a client connects to the console server */
|
|
static void ICACHE_FLASH_ATTR tcp_client_connected_cb(void *arg) {
|
|
char payload[128];
|
|
struct espconn *pespconn = (struct espconn *)arg;
|
|
|
|
os_printf("tcp_client_connected_cb(): Client connected\r\n");
|
|
|
|
if (!check_connection_access(pespconn, config.config_access)) {
|
|
os_printf("Client disconnected - no config access on this network\r\n");
|
|
espconn_disconnect(pespconn);
|
|
return;
|
|
}
|
|
|
|
espconn_regist_sentcb(pespconn, tcp_client_sent_cb);
|
|
espconn_regist_disconcb(pespconn, tcp_client_discon_cb);
|
|
espconn_regist_recvcb(pespconn, tcp_client_recv_cb);
|
|
espconn_regist_time(pespconn, 300, 1); // Specific to console only
|
|
|
|
ringbuf_reset(console_rx_buffer);
|
|
ringbuf_reset(console_tx_buffer);
|
|
|
|
os_sprintf(payload, "CMD>");
|
|
espconn_sent(pespconn, payload, os_strlen(payload));
|
|
client_sent_pending = true;
|
|
console_conn = pespconn;
|
|
}
|
|
#endif /* REMOTE_CONFIG */
|
|
|
|
// Timer cb function
|
|
void ICACHE_FLASH_ATTR timer_func(void *arg) {
|
|
uint64_t t_new;
|
|
|
|
// Do we still have to configure the AP netif?
|
|
if (do_ip_config) {
|
|
user_set_softap_ip_config();
|
|
#ifdef MDNS
|
|
if (config.mdns_mode == 2) {
|
|
struct mdns_info *info = &mdnsinfo;
|
|
struct ip_info ipconfig;
|
|
|
|
wifi_get_ip_info(SOFTAP_IF, &ipconfig);
|
|
|
|
info->host_name = "mqtt";
|
|
info->ipAddr = ipconfig.ip.addr; //ESP8266 SoftAP IP
|
|
info->server_name = "mqtt";
|
|
info->server_port = 1883;
|
|
//info->txt_data[0] = "version = now";
|
|
|
|
espconn_mdns_init(info);
|
|
}
|
|
#endif
|
|
do_ip_config = false;
|
|
}
|
|
|
|
t_new = get_long_systime();
|
|
#ifdef NTP
|
|
if (t_new - t_ntp_resync > config.ntp_interval) {
|
|
ntp_get_time();
|
|
t_ntp_resync = t_new;
|
|
}
|
|
|
|
if (ntp_sync_done()) {
|
|
uint8_t *timestr = get_timestr();
|
|
MQTT_local_publish("$SYS/broker/time", get_timestr(config.ntp_timezone), 8, 0, 0);
|
|
#ifdef SCRIPTED
|
|
check_timestamps(timestr);
|
|
#endif
|
|
}
|
|
#endif
|
|
os_timer_arm(&ptimer, 1000, 0);
|
|
}
|
|
|
|
//Priority 0 Task
|
|
static void ICACHE_FLASH_ATTR user_procTask(os_event_t * events) {
|
|
//os_printf("Sig: %d\r\n", events->sig);
|
|
//os_printf("Pub_list: %d\r\n", pub_empty());
|
|
|
|
switch (events->sig) {
|
|
case SIG_START_SERVER:
|
|
// Anything else to do here, when the broker has received its IP?
|
|
break;
|
|
#ifdef SCRIPTED
|
|
case SIG_TOPIC_RECEIVED:
|
|
{
|
|
// We check this on any signal
|
|
// pub_process();
|
|
}
|
|
break;
|
|
|
|
case SIG_SCRIPT_LOADED:
|
|
{
|
|
espconn_disconnect(downloadCon);
|
|
espconn_delete(downloadCon);
|
|
os_free(downloadCon->proto.tcp);
|
|
os_free(downloadCon);
|
|
// continue to next case and check syntax...
|
|
}
|
|
case SIG_SCRIPT_HTTP_LOADED:
|
|
{
|
|
if (read_script()) {
|
|
interpreter_syntax_check();
|
|
ringbuf_memcpy_into(console_tx_buffer, tmp_buffer, os_strlen(tmp_buffer));
|
|
ringbuf_memcpy_into(console_tx_buffer, "\r\n", 2);
|
|
}
|
|
// continue to next case and print...
|
|
}
|
|
#endif
|
|
case SIG_CONSOLE_TX:
|
|
{
|
|
ringbuf_memcpy_into(console_tx_buffer, "CMD>", 4);
|
|
}
|
|
|
|
case SIG_CONSOLE_TX_RAW:
|
|
{
|
|
struct espconn *pespconn = (struct espconn *)events->par;
|
|
console_send_response(pespconn, false);
|
|
|
|
if (pespconn != 0 && remote_console_disconnect)
|
|
espconn_disconnect(pespconn);
|
|
remote_console_disconnect = 0;
|
|
}
|
|
break;
|
|
|
|
case SIG_SERIAL_TX:
|
|
{
|
|
console_send_response(NULL, true);
|
|
}
|
|
break;
|
|
|
|
case SIG_CONSOLE_RX:
|
|
{
|
|
struct espconn *pespconn = (struct espconn *)events->par;
|
|
if (pespconn == 0 && system_output == SYSTEM_OUTPUT_NONE) {
|
|
int bytes_count = ringbuf_bytes_used(console_rx_buffer);
|
|
char data[bytes_count+1];
|
|
ringbuf_memcpy_from(data, console_rx_buffer, bytes_count);
|
|
data[bytes_count] = '\0';
|
|
#ifdef SCRIPTED
|
|
interpreter_serial_input(data, bytes_count);
|
|
#endif
|
|
} else {
|
|
console_handle_command(pespconn);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SIG_DO_NOTHING:
|
|
default:
|
|
// Intentionally ignoring other signals
|
|
os_printf("Spurious Signal received\r\n");
|
|
break;
|
|
}
|
|
|
|
// Check queued messages on any signal
|
|
#ifdef SCRIPTED
|
|
pub_process();
|
|
#endif
|
|
}
|
|
|
|
/* Callback called when the connection state of the module with an Access Point changes */
|
|
void wifi_handle_event_cb(System_Event_t * evt) {
|
|
uint16_t i;
|
|
uint8_t mac_str[20];
|
|
|
|
//os_printf("wifi_handle_event_cb: ");
|
|
switch (evt->event) {
|
|
case EVENT_STAMODE_CONNECTED:
|
|
os_printf("connect to ssid %s, channel %d\n",
|
|
evt->event_info.connected.ssid, evt->event_info.connected.channel);
|
|
my_channel = evt->event_info.connected.channel;
|
|
break;
|
|
|
|
case EVENT_STAMODE_DISCONNECTED:
|
|
os_printf("disconnect from ssid %s, reason %d\n",
|
|
evt->event_info.disconnected.ssid, evt->event_info.disconnected.reason);
|
|
connected = false;
|
|
|
|
MQTT_server_cleanupClientCons();
|
|
|
|
#ifdef MQTT_CLIENT
|
|
if (mqtt_enabled)
|
|
// Missing test for local
|
|
MQTT_Disconnect(&mqttClient);
|
|
#endif /* MQTT_CLIENT */
|
|
|
|
#ifdef MDNS
|
|
if (config.mdns_mode == 1) {
|
|
espconn_mdns_close();
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case EVENT_STAMODE_AUTHMODE_CHANGE:
|
|
os_printf("mode: %d -> %d\n", evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode);
|
|
break;
|
|
|
|
case EVENT_STAMODE_GOT_IP:
|
|
if (config.dns_addr.addr == 0) {
|
|
dns_ip.addr = dns_getserver(0);
|
|
}
|
|
|
|
os_printf("ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR ",dns:" IPSTR "\n",
|
|
IP2STR(&evt->event_info.got_ip.ip),
|
|
IP2STR(&evt->event_info.got_ip.mask), IP2STR(&evt->event_info.got_ip.gw), IP2STR(&dns_ip));
|
|
|
|
my_ip = evt->event_info.got_ip.ip;
|
|
connected = true;
|
|
|
|
#ifdef SCRIPTED
|
|
interpreter_wifi_connect();
|
|
#endif
|
|
|
|
#ifdef MQTT_CLIENT
|
|
if (mqtt_enabled)
|
|
MQTT_Connect(&mqttClient);
|
|
#endif
|
|
|
|
#ifdef NTP
|
|
if (os_strcmp(config.ntp_server, "none") != 0) {
|
|
ntp_set_server(config.ntp_server);
|
|
sntp_setservername(1, config.ntp_server);
|
|
sntp_init();
|
|
}
|
|
set_timezone(config.ntp_timezone);
|
|
#endif
|
|
|
|
#ifdef MDNS
|
|
if (config.mdns_mode == 1) {
|
|
struct mdns_info *info = &mdnsinfo;
|
|
|
|
info->host_name = "mqtt";
|
|
info->ipAddr = evt->event_info.got_ip.ip.addr; //ESP8266 station IP
|
|
info->server_name = "mqtt";
|
|
info->server_port = 1883;
|
|
//info->txt_data[0] = "version = now";
|
|
|
|
espconn_mdns_init(info);
|
|
}
|
|
#endif
|
|
|
|
// Post a Server Start message as the IP has been acquired to Task with priority 0
|
|
system_os_post(user_procTaskPrio, SIG_START_SERVER, 0);
|
|
break;
|
|
|
|
case EVENT_SOFTAPMODE_STACONNECTED:
|
|
os_sprintf(mac_str, MACSTR, MAC2STR(evt->event_info.sta_connected.mac));
|
|
os_printf("station: %s join, AID = %d\n", mac_str, evt->event_info.sta_connected.aid);
|
|
break;
|
|
|
|
case EVENT_SOFTAPMODE_STADISCONNECTED:
|
|
os_sprintf(mac_str, MACSTR, MAC2STR(evt->event_info.sta_disconnected.mac));
|
|
os_printf("station: %s leave, AID = %d\n", mac_str, evt->event_info.sta_disconnected.aid);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void ICACHE_FLASH_ATTR user_set_softap_wifi_config(void) {
|
|
struct softap_config apConfig;
|
|
|
|
wifi_softap_get_config(&apConfig); // Get config first.
|
|
|
|
os_memset(apConfig.ssid, 0, 32);
|
|
os_sprintf(apConfig.ssid, "%s", config.ap_ssid);
|
|
os_memset(apConfig.password, 0, 64);
|
|
os_sprintf(apConfig.password, "%s", config.ap_password);
|
|
if (!config.ap_open)
|
|
apConfig.authmode = AUTH_WPA_WPA2_PSK;
|
|
else
|
|
apConfig.authmode = AUTH_OPEN;
|
|
apConfig.ssid_len = 0; // or its actual length
|
|
|
|
apConfig.max_connection = MAX_CLIENTS; // how many stations can connect to ESP8266 softAP at most.
|
|
|
|
// Set ESP8266 softap config
|
|
wifi_softap_set_config(&apConfig);
|
|
}
|
|
|
|
void ICACHE_FLASH_ATTR user_set_softap_ip_config(void) {
|
|
struct ip_info info;
|
|
struct dhcps_lease dhcp_lease;
|
|
struct netif *nif;
|
|
int i;
|
|
|
|
// Configure the internal network
|
|
|
|
wifi_softap_dhcps_stop();
|
|
|
|
info.ip = config.network_addr;
|
|
ip4_addr4(&info.ip) = 1;
|
|
info.gw = info.ip;
|
|
IP4_ADDR(&info.netmask, 255, 255, 255, 0);
|
|
|
|
wifi_set_ip_info(1, &info);
|
|
|
|
dhcp_lease.start_ip = config.network_addr;
|
|
ip4_addr4(&dhcp_lease.start_ip) = 2;
|
|
dhcp_lease.end_ip = config.network_addr;
|
|
ip4_addr4(&dhcp_lease.end_ip) = 128;
|
|
wifi_softap_set_dhcps_lease(&dhcp_lease);
|
|
|
|
wifi_softap_dhcps_start();
|
|
}
|
|
|
|
void ICACHE_FLASH_ATTR user_set_station_config(void) {
|
|
struct station_config stationConf;
|
|
char hostname[40];
|
|
|
|
/* Setup AP credentials */
|
|
stationConf.bssid_set = 0;
|
|
os_sprintf(stationConf.ssid, "%s", config.ssid);
|
|
os_sprintf(stationConf.password, "%s", config.password);
|
|
wifi_station_set_config(&stationConf);
|
|
|
|
os_sprintf(hostname, "NET_%s", config.ap_ssid);
|
|
hostname[32] = '\0';
|
|
wifi_station_set_hostname(hostname);
|
|
|
|
wifi_set_event_handler_cb(wifi_handle_event_cb);
|
|
|
|
wifi_station_set_auto_connect(config.auto_connect != 0);
|
|
}
|
|
|
|
|
|
bool ICACHE_FLASH_ATTR mqtt_broker_auth(const char* username, const char *password, struct espconn *pesp_conn) {
|
|
//os_printf("connect from " IPSTR "\r\n", IP2STR((ip_addr_t *)&(pesp_conn->proto.tcp->remote_ip)));
|
|
|
|
if (os_strcmp(config.mqtt_broker_user, "none") == 0)
|
|
return true;
|
|
|
|
if (os_strcmp(username, config.mqtt_broker_user) != 0 ||
|
|
os_strcmp(password, config.mqtt_broker_password) != 0) {
|
|
os_printf("Authentication with %s/%s failed\r\n", username, password);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool ICACHE_FLASH_ATTR mqtt_broker_connect(struct espconn *pesp_conn, uint16_t client_count) {
|
|
//os_printf("connect from " IPSTR "\r\n", IP2STR((ip_addr_t *)&(pesp_conn->proto.tcp->remote_ip)));
|
|
|
|
if (!check_connection_access(pesp_conn, config.mqtt_broker_access)) {
|
|
os_printf("Client disconnected - no mqtt access from the address " IPSTR "\r\n",
|
|
IP2STR((ip_addr_t *)&(pesp_conn->proto.tcp->remote_ip)));
|
|
return false;
|
|
}
|
|
|
|
if (config.max_clients != 0 && client_count > config.max_clients) {
|
|
os_printf("Client disconnected - too many concurrent clients\r\n");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void ICACHE_FLASH_ATTR mqtt_got_retained(retained_entry *topic) {
|
|
if (config.auto_retained)
|
|
save_retainedtopics();
|
|
}
|
|
|
|
|
|
void user_init() {
|
|
struct ip_info info;
|
|
|
|
connected = false;
|
|
do_ip_config = false;
|
|
my_ip.addr = 0;
|
|
t_old = 0;
|
|
#ifdef BACKLOG
|
|
backlog_buffer = NULL;
|
|
#endif
|
|
|
|
console_rx_buffer = ringbuf_new(MAX_CON_CMD_SIZE);
|
|
console_tx_buffer = ringbuf_new(MAX_CON_SEND_SIZE);
|
|
#ifdef GPIO
|
|
gpio_init();
|
|
#endif
|
|
init_long_systime();
|
|
|
|
// Temporarily initialize the UART with 115200
|
|
UART_init_console(BIT_RATE_115200, 0, console_rx_buffer, console_tx_buffer);
|
|
|
|
os_printf("\r\n\r\nWiFi Router/MQTT Broker V2.0 starting\r\n");
|
|
|
|
// Load config
|
|
int config_res = config_load(&config);
|
|
|
|
if (config_res != 0) {
|
|
// Clear retained topics slot
|
|
blob_zero(RETAINED_SLOT, MAX_RETAINED_LEN);
|
|
}
|
|
|
|
#ifdef SCRIPTED
|
|
script_enabled = false;
|
|
if ((config_res == 0) && read_script()) {
|
|
if (interpreter_syntax_check() != -1) {
|
|
bool lockstat = config.locked;
|
|
config.locked = false;
|
|
|
|
script_enabled = true;
|
|
interpreter_config();
|
|
|
|
config.locked = lockstat;
|
|
} else {
|
|
os_printf("ERROR in script: %s\r\nScript disabled\r\n", tmp_buffer);
|
|
}
|
|
} else {
|
|
// Clear script and vars
|
|
blob_zero(SCRIPT_SLOT, MAX_SCRIPT_SIZE);
|
|
blob_zero(VARS_SLOT, MAX_FLASH_SLOTS * FLASH_SLOT_LEN);
|
|
}
|
|
#endif
|
|
|
|
// Set bit rate to config value
|
|
uart_div_modify(0, UART_CLK_FREQ / config.bit_rate);
|
|
|
|
system_output = config.system_output;
|
|
if (system_output < SYSTEM_OUTPUT_INFO) {
|
|
// all system output to /dev/null
|
|
system_set_os_print(0);
|
|
os_install_putc1(void_write_char);
|
|
}
|
|
if (system_output < SYSTEM_OUTPUT_CMD) {
|
|
// disable UART echo
|
|
UART_Echo(0);
|
|
}
|
|
|
|
// Configure the AP and start it, if required
|
|
|
|
if (config.dns_addr.addr != 0)
|
|
// We have a static DNS server
|
|
dns_ip.addr = config.dns_addr.addr;
|
|
|
|
if (config.ap_on) {
|
|
wifi_set_opmode(STATIONAP_MODE);
|
|
user_set_softap_wifi_config();
|
|
do_ip_config = true;
|
|
} else {
|
|
wifi_set_opmode(STATION_MODE);
|
|
}
|
|
|
|
if (config.my_addr.addr != 0) {
|
|
wifi_station_dhcpc_stop();
|
|
info.ip.addr = config.my_addr.addr;
|
|
info.gw.addr = config.my_gw.addr;
|
|
info.netmask.addr = config.my_netmask.addr;
|
|
wifi_set_ip_info(STATION_IF, &info);
|
|
espconn_dns_setserver(0, &dns_ip);
|
|
}
|
|
|
|
#ifdef MDNS
|
|
wifi_set_broadcast_if(STATIONAP_MODE);
|
|
#endif
|
|
|
|
#ifdef REMOTE_CONFIG
|
|
if (config.config_port != 0) {
|
|
os_printf("Starting Console TCP Server on port %d\r\n", config.config_port);
|
|
struct espconn *pCon = (struct espconn *)os_zalloc(sizeof(struct espconn));
|
|
|
|
/* Equivalent to bind */
|
|
pCon->type = ESPCONN_TCP;
|
|
pCon->state = ESPCONN_NONE;
|
|
pCon->proto.tcp = (esp_tcp *) os_zalloc(sizeof(esp_tcp));
|
|
pCon->proto.tcp->local_port = config.config_port;
|
|
|
|
/* Register callback when clients connect to the server */
|
|
espconn_regist_connectcb(pCon, tcp_client_connected_cb);
|
|
|
|
/* Put the connection in accept mode */
|
|
espconn_accept(pCon);
|
|
}
|
|
#endif
|
|
|
|
#ifdef MQTT_CLIENT
|
|
mqtt_connected = false;
|
|
mqtt_enabled = (os_strcmp(config.mqtt_host, "none") != 0);
|
|
if (mqtt_enabled) {
|
|
MQTT_InitConnection(&mqttClient, config.mqtt_host, config.mqtt_port, config.mqtt_ssl);
|
|
|
|
if (os_strcmp(config.mqtt_user, "none") == 0) {
|
|
MQTT_InitClient(&mqttClient, config.mqtt_id, 0, 0, 120, 1);
|
|
} else {
|
|
MQTT_InitClient(&mqttClient, config.mqtt_id, config.mqtt_user, config.mqtt_password, 120, 1);
|
|
}
|
|
// MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);
|
|
MQTT_OnConnected(&mqttClient, mqttConnectedCb);
|
|
MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
|
|
MQTT_OnPublished(&mqttClient, mqttPublishedCb);
|
|
MQTT_OnData(&mqttClient, mqttDataCb);
|
|
}
|
|
#endif /* MQTT_CLIENT */
|
|
|
|
remote_console_disconnect = 0;
|
|
console_conn = NULL;
|
|
|
|
// Now start the STA-Mode
|
|
user_set_station_config();
|
|
|
|
system_update_cpu_freq(config.clock_speed);
|
|
|
|
// Start the broker only if it accessible
|
|
if (config.mqtt_broker_access != 0) {
|
|
espconn_tcp_set_max_con(15);
|
|
os_printf("Max number of TCP clients: %d\r\n", espconn_tcp_get_max_con());
|
|
|
|
MQTT_server_onData(MQTT_local_DataCallback);
|
|
MQTT_server_onConnect(mqtt_broker_connect);
|
|
MQTT_server_onAuth(mqtt_broker_auth);
|
|
|
|
MQTT_server_start(1883 /*port */ , config.max_subscriptions,
|
|
config.max_retained_messages);
|
|
load_retainedtopics();
|
|
set_on_retainedtopic_cb(mqtt_got_retained);
|
|
}
|
|
|
|
//Start task
|
|
system_os_task(user_procTask, user_procTaskPrio, user_procTaskQueue, user_procTaskQueueLen);
|
|
|
|
#ifdef SCRIPTED
|
|
interpreter_init();
|
|
#endif
|
|
|
|
// Start the timer
|
|
os_timer_setfn(&ptimer, timer_func, 0);
|
|
os_timer_arm(&ptimer, 500, 0);
|
|
}
|