{"id":125,"date":"2016-12-09T09:20:57","date_gmt":"2016-12-09T16:20:57","guid":{"rendered":"http:\/\/wifitrain.link\/?page_id=125"},"modified":"2016-12-09T09:32:23","modified_gmt":"2016-12-09T16:32:23","slug":"esp8266-12f","status":"publish","type":"page","link":"http:\/\/wifitrain.link\/?page_id=125","title":{"rendered":"ESP8266-12F"},"content":{"rendered":"<pre>\/\/ Configure I\/O ports\r\nconst boolean debug = true; \/\/ true allows serial port to function\r\nconst int MOTOR_pwm = 4; \/\/ GPIO to control motor speed\r\nconst int MOTOR_dir = 5; \/\/ GPIO to control motor direction\r\nconst int LED_headlight = 3; \/\/ GPIO for head light\r\nconst int LED_cablight = 2; \/\/ GPIO for cab light\r\nconst int LED_taillight = 1; \/\/ GPIO for tail light\r\n\r\n\/\/ Configure timing and variables\r\nString CTRL = \"\"; String lastCTRL = \"\";\r\nint current_speed = 1;\r\nint target_speed = 0;\r\nint current_direction = 1;\r\nint target_direction = 1;\r\nunsigned long SPEED_timer = 0;\r\nconst int SPEED_interval = 133; \/\/ how frequently to update speed\r\nconst int SPEED_step = 3; \/\/ increment speed by this much\r\nconst int SPEED_adj = (PWMRANGE + 1) \/ 256;\r\nconst int fwd_min = 22; \/\/ minimum forward speed before motor turns\r\nconst int fwd_max = 255; \/\/ maximum formward speed\r\nconst int rev_min = 22; \/\/ minimum reverse speed before motor turns\r\nconst int rev_max = 128; \/\/ maximum reverse speed\r\nconst float SPEED_mph = 0.54; \/\/ conversion factor\r\nunsigned long CTRL_timer = 0;\r\nconst int CTRL_timeout = 5100; \/\/ client not responding timeout (ms)\r\n\r\n\/\/ Configure WIFI\r\n#include <ESP8266WiFi.h>\r\nconst char* SSID = \"sourpuss\"; \/\/ widfi SSID\r\nconst char* PASS = \"3037764157\"; \/\/ wifi password\r\nconst char* LOCO = \"DRGW101\"; \/\/ Call sign for this loco\r\n\r\n\/\/ Configure MQTT\r\n#include <AsyncMqttClient.h>\r\nconst String lastwill = String(LOCO) + \"\/IO\/online\";\r\nboolean publishInfo = true;\r\nAsyncMqttClient mqttClient;\r\n\r\nvoid setup() {\r\nSerial.begin(115200);\r\n\r\npinMode(LED_headlight, OUTPUT);\r\ndigitalWrite(LED_headlight, LOW);\r\npinMode(LED_cablight, OUTPUT);\r\ndigitalWrite(LED_cablight, LOW);\r\nif (!debug) pinMode(LED_taillight, OUTPUT);\r\nif (!debug) digitalWrite(LED_taillight, HIGH);\r\n\r\nanalogWriteFreq(200);\r\npinMode(MOTOR_pwm, OUTPUT);\r\npinMode(MOTOR_dir, OUTPUT);\r\ndigitalWrite(MOTOR_pwm, LOW);\r\ndigitalWrite(MOTOR_dir, LOW);\r\n\r\nboolean cab = false;\r\n\r\nWiFi.hostname(LOCO);\r\nWiFi.mode(WIFI_STA);\r\nWiFi.begin (SSID, PASS);\r\nSerial.print(\"\\r\\nConnecting to \");\r\nSerial.print(SSID);\r\nwhile (WiFi.status() != WL_CONNECTED) {\r\ndelay(250);\r\ncab = !cab;\r\nSerial.print(\".\");\r\ndigitalWrite(LED_cablight, cab);\r\n}\r\nSerial.println(WiFi.localIP());\r\ndigitalWrite(LED_cablight, LOW);\r\n\r\nmqttClient.onConnect(onMqttConnect);\r\nmqttClient.onDisconnect(onMqttDisconnect);\r\nmqttClient.onSubscribe(onMqttSubscribe);\r\nmqttClient.onUnsubscribe(onMqttUnsubscribe);\r\nmqttClient.onMessage(onMqttMessage);\r\nmqttClient.onPublish(onMqttPublish);\r\nmqttClient.setServer(IPAddress(10, 10, 1, 1), 1883);\r\n\r\n\/\/mqttClient.setKeepAlive(5).setCleanSession(false).setWill(\"\/IO\/online\", 2, true, \"0\").setCredentials(\"username\", \"password\").setClientId(LOCO);\r\nmqttClient.setKeepAlive(5).setCleanSession(false).setWill(lastwill.c_str(), 2, true, \"false\").setClientId(LOCO);\r\nSerial.println(\"Connecting to MQTT...\");\r\nmqttClient.connect();\r\n} \/\/ setup\r\n\r\nvoid loop() {\r\nunsigned long NOW = millis();\r\nunsigned int flag = 0;\r\nString mqtt = \"\";\r\nchar buf[10];\r\n\r\nif (NOW >= SPEED_timer) {\r\nflag = 0;\r\nif (current_direction != target_direction) {\r\ncurrent_speed -= SPEED_step;\r\nif (current_speed <= fwd_min) current_speed = 0; flag=1; } else { if (target_speed < current_speed) { current_speed -= SPEED_step; if (current_speed <= fwd_min) current_speed = 0; if (current_speed < target_speed) target_speed = current_speed; flag=1; } if (target_speed > current_speed) {\r\nif (current_speed <= fwd_min) current_speed = fwd_min; current_speed += SPEED_step; if (current_speed > target_speed) target_speed = current_speed;\r\nflag=1;\r\n}\r\n}\r\n\r\n\/\/if (current_speed < 0) current_speed = 0; if (current_speed < fwd_min) { if (current_direction != target_direction) { mqtt = String(LOCO) + \"\/IO\/dir\"; sprintf (buf, \"%d\", target_direction); mqttClient.publish(mqtt.c_str(), 2, false, buf); } current_speed = 0; current_direction = target_direction; digitalWrite(LED_cablight, HIGH); } else digitalWrite(LED_cablight, LOW); if (current_direction < 0) { digitalWrite(LED_headlight, LOW); digitalWrite(LED_taillight, LOW); if (target_speed > rev_max) target_speed = rev_max;\r\nif (current_speed > rev_max) current_speed = rev_max;\r\n}\r\nif (current_direction > 0) {\r\ndigitalWrite(LED_headlight, HIGH);\r\ndigitalWrite(LED_taillight, HIGH);\r\nif (target_speed > fwd_max) target_speed = fwd_max;\r\nif (current_speed > fwd_max) current_speed = fwd_max;\r\n}\r\n\r\nif (flag) { \/\/ Only update if something changed\r\nif (current_direction >= 0) digitalWrite(MOTOR_dir, LOW);\r\nelse digitalWrite(MOTOR_dir, HIGH);\r\nanalogWrite(MOTOR_pwm, current_speed * SPEED_adj);\r\n\r\nmqtt = String(LOCO) + \"\/IO\/speed\";\r\nsprintf (buf, \"%d\", current_speed);\r\nmqttClient.publish(mqtt.c_str(), 2, false, buf);\r\nSerial.print(\"Speed: \");\r\nSerial.println(current_speed);\r\n}\r\n\r\nSPEED_timer = NOW + SPEED_interval;\r\n} \/\/ NOW >= SPEED_timer\r\n\r\nif ((CTRL != \"\") && (NOW >= CTRL_timer)) {\r\n\/\/ Release control from non-responding client\r\nSerial.println(\"Client stopped responding\");\r\nCTRL = \"\";\r\ntarget_speed = 0;\r\ntarget_direction = 1;\r\n\r\nmqtt = String(LOCO) + \"\/CLIENT\/\" + CTRL + \"\/#\";\r\nmqttClient.unsubscribe(mqtt.c_str());\r\n\r\nmqtt = String(LOCO) + \"\/CLIENT\/\" + CTRL + \"\/has_ctrl\";\r\nmqttClient.publish(mqtt.c_str(), 2, false, \"\");\r\n\r\nmqtt = String(LOCO) + \"\/IO\/ctrl\";\r\nmqttClient.publish(mqtt.c_str(), 2, true, \"true\");\r\n}\r\n} \/\/ loop\r\n\r\nvoid onMqttConnect(bool sessionPresent) {\r\nSerial.println(\"** Connected to the broker **\");\r\nSerial.print(\"Session present: \");\r\nSerial.println(sessionPresent);\r\n\r\nString mqtt = \"\";\r\nString mqttPub = \"\";\r\nchar buf[10];\r\n\r\nmqtt = String(LOCO) + \"\/IO\/#\";\r\nuint16_t packetIdSub = mqttClient.subscribe(mqtt.c_str(), 2);\r\n\r\nmqtt = String(LOCO) + \"\/IO\/online\";\r\nmqttClient.publish(mqtt.c_str(), 2, true, \"true\");\r\n\r\nmqtt = String(LOCO) + \"\/IO\/fwd_min\";\r\nsprintf (buf, \"%d\", fwd_min);\r\nmqttClient.publish(mqtt.c_str(), 2, true, buf);\r\n\r\nmqtt = String(LOCO) + \"\/IO\/fwd_max\";\r\nsprintf (buf, \"%d\", fwd_max);\r\nmqttClient.publish(mqtt.c_str(), 2, true, buf);\r\n\r\nmqtt = String(LOCO) + \"\/IO\/rev_min\";\r\nsprintf (buf, \"%d\", rev_min);\r\nmqttClient.publish(mqtt.c_str(), 2, true, buf);\r\n\r\nmqtt = String(LOCO) + \"\/IO\/rev_max\";\r\nsprintf (buf, \"%d\", rev_max);\r\nmqttClient.publish(mqtt.c_str(), 2, true, buf);\r\n\r\nmqtt = String(LOCO) + \"\/IO\/mph\";\r\ndtostrf(SPEED_mph, 9, 6, buf);\r\nmqttClient.publish(mqtt.c_str(), 2, true, buf);\r\n\r\nmqtt = String(LOCO) + \"\/IO\/speed\";\r\nsprintf (buf, \"%d\", current_speed);\r\nmqttClient.publish(mqtt.c_str(), 2, true, buf);\r\n\r\nmqtt = String(LOCO) + \"\/IO\/dir\";\r\nsprintf (buf, \"%d\", current_direction);\r\nmqttClient.publish(mqtt.c_str(), 2, true, buf);\r\n\r\nmqtt = String(LOCO) + \"\/IO\/ctrl\";\r\nmqttClient.publish(mqtt.c_str(), 2, true, \"true\");\r\n}\r\n\r\nvoid onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {\r\nSerial.println(\"** Disconnected from the broker **\");\r\nSerial.println(\"Reconnecting to MQTT...\");\r\nmqttClient.connect();\r\n}\r\n\r\nvoid onMqttSubscribe(uint16_t packetId, uint8_t qos) {\r\nSerial.println(\"** Subscribe acknowledged **\");\r\nSerial.print(\" packetId: \");\r\nSerial.println(packetId);\r\nSerial.print(\" qos: \");\r\nSerial.println(qos);\r\n}\r\n\r\nvoid onMqttUnsubscribe(uint16_t packetId) {\r\nSerial.println(\"** Unsubscribe acknowledged **\");\r\nSerial.print(\" packetId: \");\r\nSerial.println(packetId);\r\n}\r\n\r\nvoid onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {\r\nSerial.println(\"** Publish received **\");\r\nSerial.print(\" topic: \");\r\nSerial.println(topic);\r\n\/*\r\nSerial.print(\" qos: \");\r\nSerial.println(properties.qos);\r\nSerial.print(\" dup: \");\r\nSerial.println(properties.dup);\r\nSerial.print(\" retain: \");\r\nSerial.println(properties.retain);\r\nSerial.print(\" len: \");\r\nSerial.println(len);\r\nSerial.print(\" index: \");\r\nSerial.println(index);\r\nSerial.print(\" total: \");\r\nSerial.println(total);\r\nSerial.print(\" payload: '\");\r\nSerial.print(payload);\r\nSerial.println(\"'\");\r\n*\/\r\n\/\/String data = String(payload).substring(0,len);\r\nchar data[len+1];\r\nstrncpy(data, payload, len);\r\ndata[len] = '\\0';\r\n\r\nSerial.print(\" data: '\");\r\nSerial.print(data);\r\nSerial.println(\"'\");\r\n\r\nunsigned long NOW = millis();\r\nString cmd = String(topic).substring(String(LOCO).length() + 1);\r\nString mqtt = \"\";\r\nchar buf[4];\r\n\r\nSerial.println(\"CMD: '\" + cmd + \"'\");\r\n\r\nif ((CTRL == \"\") && (cmd = \"IO\/ctrl\") && (len == 23)) {\r\nCTRL = String(data);\r\nlastCTRL = CTRL;\r\n\r\nmqtt = String(LOCO) + \"\/IO\/ctrl\";\r\nmqttClient.publish(mqtt.c_str(), 2, true, \"false\");\r\n\r\nmqtt = String(LOCO) + \"\/CLIENT\/\" + CTRL + \"\/#\";\r\nuint16_t packetIdSub = mqttClient.subscribe(mqtt.c_str(), 2);\r\n\r\nmqtt = String(LOCO) + \"\/CLIENT\/\" + CTRL + \"\/has_ctrl\";\r\nmqttClient.publish(mqtt.c_str(), 2, false, \"true\");\r\n\r\nCTRL_timer = NOW + CTRL_timeout;\r\n}\r\n\r\nif (cmd == \"CLIENT\/\" + CTRL + \"\/ping\") {\r\nSerial.print(\"PING: \");\r\nSerial.println(data);\r\nCTRL_timer = NOW + CTRL_timeout;\r\n}\r\n\r\nif (cmd == \"CLIENT\/\" + CTRL + \"\/has_ctrl\") {\r\nif (String(data) != \"true\") {\r\nSerial.println(\"Client requested disconnect\");\r\nmqtt = String(LOCO) + \"\/CLIENT\/\" + CTRL + \"\/#\";\r\nmqttClient.unsubscribe(mqtt.c_str());\r\nmqtt = String(LOCO) + \"\/IO\/ctrl\";\r\nmqttClient.publish(mqtt.c_str(), 2, true, \"true\");\r\nCTRL = \"\";\r\ntarget_speed = 0;\r\ntarget_direction = 1;\r\n}\r\n}\r\n\r\nif (cmd == \"CLIENT\/\" + CTRL + \"\/set_dir\") {\r\ntarget_direction = atoi(data);\r\n\/\/target_direction = data.toInt();\r\nSerial.print(\"DIR: \");\r\nSerial.println(target_direction);\r\nCTRL_timer = NOW + CTRL_timeout;\r\n}\r\n\r\nif (cmd == \"CLIENT\/\" + CTRL + \"\/set_spd\") {\r\ntarget_speed = atoi(data);\r\n\/\/target_speed = data.toInt();\r\nSerial.print(\"SPEED: \");\r\nSerial.println(target_speed);\r\nCTRL_timer = NOW + CTRL_timeout;\r\n}\r\n}\r\n\r\nvoid onMqttPublish(uint16_t packetId) {\r\nSerial.println(\"** Publish acknowledged **\");\r\nSerial.print(\" packetId: \");\r\nSerial.println(packetId);\r\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\/\/ Configure I\/O ports const boolean debug = true; \/\/ true allows serial port to function const int MOTOR_pwm = 4; \/\/ GPIO to control motor speed const int MOTOR_dir = 5; \/\/ GPIO to control motor direction const int LED_headlight = 3; \/\/ GPIO for head light const int LED_cablight = 2; \/\/ GPIO [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-125","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"http:\/\/wifitrain.link\/index.php?rest_route=\/wp\/v2\/pages\/125","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/wifitrain.link\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"http:\/\/wifitrain.link\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"http:\/\/wifitrain.link\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/wifitrain.link\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=125"}],"version-history":[{"count":5,"href":"http:\/\/wifitrain.link\/index.php?rest_route=\/wp\/v2\/pages\/125\/revisions"}],"predecessor-version":[{"id":157,"href":"http:\/\/wifitrain.link\/index.php?rest_route=\/wp\/v2\/pages\/125\/revisions\/157"}],"wp:attachment":[{"href":"http:\/\/wifitrain.link\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=125"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}