Coding Chase - Projects

My 3D Hub

Thank You For Donating:

Ikeeki (linux-sunxi@irc.freenode.net)
Computer Troubleshooters Brasil

Monday 7 November 2016

IoT Projects - ESP8266 [CTC-3D Printer Upgrade] III

A while as passed since my last post on the blog - work, family and life in general have rolled by and although I haven't stopped experimenting and learning, not much time got left to update my humble journal.

After the CTC and lots of both tinkering and playing with materials, I got a Geeetech Prusa I3X assembling kit.

That story deserves a post of its own, but now that all is working in the office, I decided to officially declare open my personal 3D printing lab...!


Remodeling the workbench to accommodate both devices, plus re-installing the LED lighting to the workbench frame in order to light up the entire area payed off, however the small micro-controller solution I was running with the ESP8266-01 needed to grow to three relays, so I decided to upgrade to an ESP8266-12.

At this point, the web app solution I had was also quite outdated (using MEAN.js) and upgrading it was beginning to become quite the endeavor.

That was when I found out about this project on Github:

Crouton MQTT IOT Dashboard

It looked awesome and the MQTT messaging architecture seemed very well thought out, so I decided to give it a try.

However, that meant re-rewriting the ESP lua code I already had and update the solution to Crouton's way of doing things.

 Below is the sample code I came up with in order to use the ESP with Crouton (based off of Crouton's included example code). Although it was working properly, I would still have to work out some extra validations, such as reconnecting to WiFi and/or the MQTT broker:

init.lua

print('init.lua ver 1.2')
wifi.setmode(wifi.STATION)
print('set mode=STATION (mode='..wifi.getmode()..')')
print('MAC: ',wifi.sta.getmac())
print('chip: ',node.chipid())
print('heap: ',node.heap())

--include json encoder/decoder
json = require "cjson"

-- wifi config start
wifi.sta.config("ssid","password")
-- wifi config end

print('Starting up in 5 seconds!')

function startup()
    print('Starting up...')
    dofile('main.lua')
    end

tmr.alarm(0,5000,0,startup)




main.lua

-- pin stuff
print("setting up pins")
ledlightingPin = 1
toggleSwitchCTCPin = 3
toggleSwitchPrusaPin = 5

gpio.mode(ledlightingPin, gpio.OUTPUT)
gpio.write(ledlightingPin, gpio.HIGH)

gpio.mode(toggleSwitchCTCPin, gpio.OUTPUT)
gpio.write(toggleSwitchCTCPin, gpio.HIGH)

gpio.mode(toggleSwitchPrusaPin, gpio.OUTPUT)
gpio.write(toggleSwitchPrusaPin, gpio.HIGH)

-- Configuration to connect to the MQTT broker.
BROKER = "m11.cloudmqtt.com"   -- Ip/hostname of MQTT broker
BRPORT = 22002             -- MQTT broker port
SECURE = 1                  -- 1 YES / 0 NO
BRUSER = "esp8266-12-" ..  node.chipid()           -- If MQTT authenitcation is used then define the user
BRPWD  = node.chipid()            -- The above user password
CLIENTID = "esp8266-12-" ..  node.chipid() -- The MQTT ID. Change to something you like
print("Device name printed below:")
print(CLIENTID)

--deviceJson
deviceInfo = {}
deviceInfo["endPoints"] = {}
deviceInfo["endPoints"]["ledlighting"] = {}
deviceInfo["endPoints"]["ledlighting"]["values"] = {}
deviceInfo["endPoints"]["ledlighting"]["values"]["value"] = true
deviceInfo["endPoints"]["ledlighting"]["labels"] = {}
deviceInfo["endPoints"]["ledlighting"]["labels"]["true"] = "ON"
deviceInfo["endPoints"]["ledlighting"]["labels"]["false"] = "OFF"
deviceInfo["endPoints"]["ledlighting"]["card-type"] = "crouton-simple-toggle"
deviceInfo["endPoints"]["ledlighting"]["title"] = "Iluminação"

deviceInfo["endPoints"]["toggleSwitchCTC"] = {}
deviceInfo["endPoints"]["toggleSwitchCTC"]["values"] = {}
deviceInfo["endPoints"]["toggleSwitchCTC"]["values"]["value"] = true
deviceInfo["endPoints"]["toggleSwitchCTC"]["labels"] = {}
deviceInfo["endPoints"]["toggleSwitchCTC"]["labels"]["true"] = "ON"
deviceInfo["endPoints"]["toggleSwitchCTC"]["labels"]["false"] = "OFF"
deviceInfo["endPoints"]["toggleSwitchCTC"]["card-type"] = "crouton-simple-toggle"
deviceInfo["endPoints"]["toggleSwitchCTC"]["title"] = "CTC-3D"

deviceInfo["endPoints"]["toggleSwitchPrusa"] = {}
deviceInfo["endPoints"]["toggleSwitchPrusa"]["values"] = {}
deviceInfo["endPoints"]["toggleSwitchPrusa"]["values"]["value"] = true
deviceInfo["endPoints"]["toggleSwitchPrusa"]["labels"] = {}
deviceInfo["endPoints"]["toggleSwitchPrusa"]["labels"]["true"] = "ON"
deviceInfo["endPoints"]["toggleSwitchPrusa"]["labels"]["false"] = "OFF"
deviceInfo["endPoints"]["toggleSwitchPrusa"]["card-type"] = "crouton-simple-toggle"
deviceInfo["endPoints"]["toggleSwitchPrusa"]["title"] = "Prusa I3 X"

deviceInfo["endPoints"]["youTubeStreamCTC"] = {}
deviceInfo["endPoints"]["youTubeStreamCTC"]["values"] = {}
deviceInfo["endPoints"]["youTubeStreamCTC"]["values"]["youtubeID"] = "GZnb3jQ2YZo"
deviceInfo["endPoints"]["youTubeStreamCTC"]["card-type"] = "crouton-video-youtube"
deviceInfo["endPoints"]["youTubeStreamCTC"]["title"] = "CTC-3D"

deviceInfo["endPoints"]["youTubeStreamPrusa"] = {}
deviceInfo["endPoints"]["youTubeStreamPrusa"]["values"] = {}
deviceInfo["endPoints"]["youTubeStreamPrusa"]["values"]["youtubeID"] = "GZnb3jQ2YZo"
deviceInfo["endPoints"]["youTubeStreamPrusa"]["card-type"] = "crouton-video-youtube"
deviceInfo["endPoints"]["youTubeStreamPrusa"]["title"] = "Prusa I3 X"



deviceJson = {}
deviceJson["deviceInfo"] = deviceInfo


-- MQTT topics to subscribe
topics = {
  "/inbox/"..CLIENTID.."/deviceInfo",
  "/inbox/"..CLIENTID.."/ledlighting",
  "/inbox/"..CLIENTID.."/toggleSwitchCTC",
  "/inbox/"..CLIENTID.."/toggleSwitchPrusa",
  "/inbox/"..CLIENTID.."/youTubeStreamCTC",
  "/inbox/"..CLIENTID.."/youTubeStreamPrusa"
} -- Add/remove topics to the array


-- Control variables.
pub_sem = 0         -- MQTT Publish semaphore. Stops the publishing when the previous hasn't ended
current_topic  = 1  -- variable for one currently being subscribed to
topicsub_delay = 50 -- microseconds between subscription attempts, worked for me (local network) down to 5...YMMV

-- connect to the broker
print "Connecting to MQTT broker. Please wait..."
m = mqtt.Client( CLIENTID, 60, BRUSER, BRPWD)
m:connect( BROKER , BRPORT, SECURE, function(conn) end)
m:on("connect", function(con)
  print ("connected")
  publish_data("/outbox/"..CLIENTID.."/deviceInfo", json.encode(deviceJson))
  mqtt_sub()
end)

--subscribe to the list of topics
function mqtt_sub()
     if table.getn(topics) >= current_topic then
          m:subscribe(topics[current_topic] , 0, function(conn,topic,message)
            print("Subscribed a topic ...")
          end)
          current_topic = current_topic + 1  -- Goto next topic
          --set the timer to rerun the loop as long there is topics to subscribe
          tmr.alarm(5, topicsub_delay, 0, mqtt_sub )
     end
end


-- Sample publish functions:
function publish_data(topic, data)
   if pub_sem == 0 then  -- Is the semaphore set=
     pub_sem = 1  -- Nop. Let's block it
     m:publish(topic,data,0,0, function(conn)
        -- Callback function. We've sent the data
        -- print("Sending: " .. data .." to " .. topic)
        pub_sem = 0  -- Unblock the semaphore
     end)
   end
end

function explode(d,p) -- (separator,string)
  local t, ll
  t={}
  ll=0
  if(#p == 1) then return {p} end
    while true do
      l=string.find(p,d,ll,true) -- find the next d in the string
      if l~=nil then -- if "not not" found then..
        table.insert(t, string.sub(p,ll,l-1)) -- Save it in our array.
        ll=l+1 -- save just after where we found it for searching next time.
      else
        table.insert(t, string.sub(p,ll)) -- Save what's left in our array.
        break -- Break at end, as it should be, according to the lua manual.
      end
    end
  return t
end

-- Recieving data
m:on("message", function(conn, topic, msg)
  topicTable = explode("/",topic)

  box = topicTable[2]
  name = topicTable[3]
  address = topicTable[4]

  if box == "inbox" then
    if address == "ledlighting" then
      toggleLEDlighting(msg)
    end
    if address == "toggleSwitchCTC" then
      toggleSwitchCTC(msg)
    end
    if address == "toggleSwitchPrusa" then
      toggleSwitchPrusa(msg)
    end
  end

  if box == "inbox" and address == "deviceInfo" then
    deviceJson["deviceInfo"]["endPoints"]["ledlighting"]["values"]["value"] = (gpio.read(ledlightingPin) ~= 0) and true or false
    deviceJson["deviceInfo"]["endPoints"]["toggleSwitchCTC"]["values"]["value"] = (gpio.read(toggleSwitchCTCPin) ~= 0) and true or false
    deviceJson["deviceInfo"]["endPoints"]["toggleSwitchPrusa"]["values"]["value"] = (gpio.read(toggleSwitchPrusaPin) ~= 0) and true or false
    publish_data("/outbox/"..CLIENTID.."/deviceInfo", json.encode(deviceJson))
  end
end )

m:lwt("/outbox/"..CLIENTID.."/lwt", "anythinghere", 0, 0)
m:on("offline", function(con) print ("offline") end)

-------- Should split file but we will later.. above code for mqtt .. below is the esp function

function toggleLEDlighting (msg)
  msgObj = json.decode(msg)

  if msgObj["value"] then
    gpio.write(ledlightingPin, gpio.HIGH)
  else
    gpio.write(ledlightingPin, gpio.LOW)
  end
  publish_data("/outbox/"..CLIENTID.."/ledlighting", msg)
end

function toggleSwitchCTC (msg)
  msgObj = json.decode(msg)

  if msgObj["value"] then
    gpio.write(toggleSwitchCTCPin, gpio.HIGH)
  else
    gpio.write(toggleSwitchCTCPin, gpio.LOW)
  end
  publish_data("/outbox/"..CLIENTID.."/toggleSwitchCTC", msg)
end

function toggleSwitchPrusa (msg)
  msgObj = json.decode(msg)

  if msgObj["value"] then
    gpio.write(toggleSwitchPrusaPin, gpio.HIGH)
  else
    gpio.write(toggleSwitchPrusaPin, gpio.LOW)
  end
  publish_data("/outbox/"..CLIENTID.."/toggleSwitchPrusa", msg)
end


Some additional considerations:
  1. working with CloudMQTT, using a free account
  2. CloudMQTT supports secure web sockets as well as secure MQTT connection over SSL (which I decided to try out)
  3. working with NodeMCU and Lua on the ESP:
    1. used https://nodemcu-build.com/ to build my custom firmware;
    2. nodemcu-dev-11-modules-2016-10-09-19-15-15-integer;
    3. included modules: adc, cjson, file, gpio, mqtt, net, node, pwm, tmr, uart, wifi
  4. contributing for the Crouton Dashboard project to include secure web sockets support

The Crouton Dashboard project is still going, however it turned out pretty well in replacing my outdated, custom web app solution.

So at this point, the ESP8266 module (-12 variant) running NodeMCU plus the use of the Crouton Dashboard were a working solution, only requiring a basic circuit to include 3 relays in order to turn on/off both printers and the LED lighting - plus a 3d printed case.

Using a free CloudMQTT account, I set up the following users and ACLs:

crouton-client:

/inbox/esp8266-12-<chipid>/#    read - false / write - true
/outbox/esp8266-12-<chipid>/#    read - true / write - false

esp8266-12-<chipid>:

/inbox/esp8266-12-<chipid>/#    read - true / write - false
/outbox/esp8266-12-<chipid>/#    read - false / write - true


And then used CloudMQTT's own web socket client to view the messages being exchanged across topics.

All of this lead to a definitive, working solution which remained stable for several weeks non-stop, allowing me to remotely turn on/off any of the 3D printers, as well as the lighting.
The video streaming was still to be published to youtube live, so by then I would just be accessing it through the Octoprint instances.
 


... and that was when I remembered about the Oak Project by Digistump.

(to be continued)

Wednesday 22 June 2016

SailfishOS Ports

SailfishOS - True Independent Mobile OS


A couple of years back, I had the chance to try out the Jolla Phone running SailfishOS and even do some app development for it.

Recently, and without the device at hand, I thought about updating the code, as SailfishOS has already gone 2.0 - and since I'm a proud owner of a Galaxy Samsung S4 smartphone, I went about looking for any available ROMs I could try out...

... but in the end found myself producing builds for the device, and things progressed quite well, so with big thanks to everyone else before me like JustSueMe, Simon Van der Veldt, and the porters at #sailfishos-porters@irc.freenode.net, below are several links to resources, such as ROM builds to try out, porting status and active discussion on the subject!

So if you have one of these Samsung S4 GT-I9505 LTE, a.k.a. "jfltexx" and would like to try out something different, your feedback will be very appreciated:

Mer Wiki Device Page
XDA Porting Thread
SailfishOS ROM Download
Youtube Video Gallery