 #endif
 #include <ESP8266HTTPClient.h>
 #include <ESP8266httpUpdate.h>
+#include <PubSubClient.h>
 #include <Ticker.h>
 
-#define SSID1		"ssid1"
-#define PSK1		"psk1"
-#define SSID2		"ssid2"
-#define PSK2		"psk2"
+extern "C" {
+#include "osapi.h"
+#include "ets_sys.h"
+#include "user_interface.h"
+}
+
+#define NEURITE_CMD_BUF_SIZE		256
+#define NEURITE_UID_LEN			32
+#define NEURITE_TOPIC_LEN		64
 
 #define NEURITE_LED	13
 #define NEURITE_BUTTON	0
 
+#define __bzero(m,s)	memset(m,0,s)
+
+struct cmd_parser_s;
+typedef void (*cmd_parser_cb_fp)(struct cmd_parser_s *cp);
+
+struct cmd_parser_s {
+	char *buf;
+	uint16_t buf_size;
+	uint16_t data_len;
+	bool cmd_begin;
+	cmd_parser_cb_fp callback;
+};
+
+struct neurite_mqtt_cfg_s {
+	char uid[NEURITE_UID_LEN];
+	char topic_to[NEURITE_TOPIC_LEN];
+	char topic_from[NEURITE_TOPIC_LEN];
+};
+
+struct neurite_data_s {
+	bool wifi_connected;
+	bool mqtt_connected;
+	struct neurite_mqtt_cfg_s nmcfg;
+	struct cmd_parser_s *cp;
+};
+
+struct neurite_data_s g_nd;
+struct cmd_parser_s g_cp;
+
+#if 0
+RINGBUF cmd_rx_rb;
+char cmd_rx_buf[256];
+#endif
+char cmd_buf[NEURITE_CMD_BUF_SIZE];
+
 #ifdef WIFI_CONFIG_MULTI
 ESP8266WiFiMulti WiFiMulti;
 #endif
 Ticker ticker_worker;
 Ticker ticker_led;
-
-//static char *ota_url = "http://accrete.org:8080/firmware/esp.bin";
-static char *ota_url = "http://192.168.100.154/firmware/esp.bin";
+WiFiClient wifi_cli;
+PubSubClient mqtt_cli(wifi_cli);
+
+static char uid[32];
 
 enum {
 	WORKER_ST_0 = 0,

}

#ifndef WIFI_CONFIG_MULTI
static int setup_wifi(char *ssid, char *password)
{
	if (!ssid || !password) {
		log_err("invalid args\n\r");
		return -1;
	}

	Serial.println();
	Serial.print("Connecting to ");
	Serial.println(ssid);

	WiFi.begin(ssid, password);
}
#endif

static inline void config_wifi(void)
{
#ifdef WIFI_CONFIG_MULTI
	WiFiMulti.addAP(SSID1, PSK1);
	WiFiMulti.addAP(SSID2, PSK2);
#else
	setup_wifi(SSID1, PSK1);
#endif
}

static inline bool check_wifi_status(void)
{
#ifdef WIFI_CONFIG_MULTI
	return (WiFiMulti.run() == WL_CONNECTED);


			if (digitalRead(NEURITE_BUTTON) == LOW) {
				ticker_led.detach();
				ota_over_http(OTA_URL_DEFAULT);
			}
			update_worker_state(WORKER_ST_2);
			break;
		case WORKER_ST_2:
			if (!mqtt_check_status()) {
				mqtt_connect(nd);
				break;
			}
			mqtt_cli.subscribe(nd->nmcfg.topic_from);
			char payload_buf[32];
			dbg_assert(payload_buf);
			sprintf(payload_buf, "checkin: %s", nd->nmcfg.uid);
			mqtt_cli.publish(nd->nmcfg.topic_to, (const char *)payload_buf);

			ticker_led.detach();
			ticker_led.attach_ms(50, ticker_led_breath);
			start_child_worker();
			update_worker_state(WORKER_ST_3);
			break;
		case WORKER_ST_3:
			mqtt_cli.loop();
			break;
		default:
			log_err("unknown worker state: %d\n\r", worker_st);
