Wednesday, November 4, 2015

Raspberry PI2 + Thingspeak on JESSIE


   This is a follow-up for the previous Raspberry PI2 - Standalone Thingspeak server installation

   Because many people have encountered lots of issues with the installation, mainly r8188eu WIFI chipset driver issues or strange compile problems, I was thinking to give a chance also to the new RASPBIAN Jessie, maybe it might be possible to make life easier for many of us.

   The setup environment remain the same, same remain the SD Card flashing process, so please take a look first at : Raspberry PI2 - Standalone Thingspeak server installation

   First thing: because I use RPI2 board headless, I have disabled the new default boot to graphical interface that Jessie has, CLI is more than enough for me.


   GOOD NEWS!! The issue with the r8188eu WIFI seems to be solved. At least my dongle worked this time out of the box, nothing fancy to be done anymore.



   Below is the full transcript of a Thingspeak Server installation process finished about 30 min ago, using a fresh new RASPBIAN Jessie image:


System Update & required packages install

  • Switched over to SSH remote access with Putty - accept new key
  • Change "pi" account password:
                  pi@RPIMON1~$passwd
  • Set ROOT password, so you can then use root (just for very, very special things!)
              pi@RPIMON1~$sudo passwd root
  • System Update & upgrade  :
              pi@RPIMON1~$sudo apt-get update            
              pi@RPIMON1~$sudo apt-get upgrade          
              pi@RPIMON1~$sudo apt-get dist-upgrade   
              pi@RPIMON1~$sudo sync

  • Reboot:
            pi@RPIMON1~$ sudo reboot
  • INSTALL Required packages:
           pi@RPIMON1~$sudo apt-get -y install build-essential git mysql-server mysql-client 
                                       libmysqlclient-dev libxml2-dev libxslt-dev libssl-dev libsqlite3-dev  

 MySQL Database configuration

    pi@RPIMON1~$mysql --user=root mysql -p useyourpasswd here
    pi@RPIMON1~$mysql> CREATE USER 'thing'@'localhost' IDENTIFIED BY 'speak’;
    pi@RPIMON1~$mysql> GRANT ALL PRIVILEGES ON *.* TO 'thing'@'localhost' WITH GRANT OPTION;
    pi@RPIMON1~$mysql> commit;
    pi@RPIMON1~$mysql> exit;


Ruby / Rails install

          pi@RPIMON1~$wget http://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.5.tar.gz
          pi@RPIMON1~$tar xvzf ruby-2.1.5.tar.gz
          pi@RPIMON1~$cd ruby-2.1.5
          pi@RPIMON1~$./configure
          pi@RPIMON1~$make


MAKE RESULT:

  Files:        962
  Classes:     1414 ( 566 undocumented)
  Modules:      268 (  87 undocumented)
  Constants:   2098 ( 624 undocumented)
  Attributes:  1146 ( 272 undocumented)
  Methods:    10651 (2228 undocumented)

  Total:      15577 (3777 undocumented)
   75.75% documented

  Elapsed: 812.6s
 

(That means you need to be VERY patient thru the entire process ! :) )


          pi@RPIMON1~$sudo make install
          pi@RPIMON1~$cd ..
          pi@RPIMON1~$echo "gem: --no-rdoc --no-ri" >> ${HOME}/.gemrc
          pi@RPIMON1~$sudo gem install rails
 



THINGSPEAK SERVER INSTALL

    pi@RPIMON1~$git clone https://github.com/iobridge/thingspeak.git
    pi@RPIMON1~$cp thingspeak/config/database.yml.example thingspeak/config/database.yml
    pi@RPIMON1~$cd thingspeak
    pi@RPIMON1~$bundle install
    pi@RPIMON1~$bundle exec rake db:create

   
Check MYSQL DB:

    pi@RPIMON1~$mysql --user=root mysql -p
    pi@RPIMON1~$mysql> show databases;

#+----------------------------  +
#| Database                        |
#+----------------------------  +
#| information_schema        |
#| mysql                              |
#| performance_schema      |
#| thingspeak_development |
#| thingspeak_test               |
#+------------------------------+


     pi@RPIMON1~$mysql> exit; 

IF MYSQL DB OK  then :

     pi@RPIMON1~$bundle exec rake db:schema:load





 RUN the THINGSPEAK SERVER:

    pi@RPIMON1 ~/yourthingspeak $ rails server webrick.




 That's it! Prepare yourself for about 4 hours of patience :)

 Waiting your feedback about!


Friday, August 28, 2015

ESP8266 - NodeMCU - I2C - Programming considerations







The story behind:

  Many people are complaining about I2C communications problems, mostly related with the NodeMCU LUA.

  I found out that many of the related problems are generated from a easy to fall in trap, generated by the way how code is executed in case of a step-by-step debug run or using a interpreter console, as in our above NodeMCU LUA case.

   Let's take a very simple example code and with the help of a Oscilloscope let's see what's happening exactly. I have choosen a LM75 I2C temperature sensor for our example, as been widely used and also people heavily complained about communication problems with. For more details about the code take a look at the LM75 Temperature sensor Article.

address = 0x48  -- LM75 I2C Address
temp_reg = 0     -- temp reg

bus = 0              -- I2C bus
sda, scl = 2, 1   -- Used pins for SDA and SCL
 

-- init I2C Bus  
   i2c.setup(bus, sda, scl, i2c.SLOW)
 

-- LM 75 Communication
  i2c.start(bus)     
  i2c.address(bus, address, i2c.TRANSMITTER)
  i2c.write(bus, temp_reg)
  i2c.stop(bus)


  i2c.start(bus)
  i2c.address(bus, address, i2c.RECEIVER)
  c=i2c.read(bus, 2)
  i2c.stop(bus)

  h,l = string.byte(c,1,2)
  if h > 127 then h = h - 255 end       
  if l > 127 then l = 5 else l = 0 end  
  temp=string.format("%d.%d", h,l)
  print(temp)


If you take the code from above, save it on ESP8266 module as lm75_test.lua and run it after that as
dofile("lm75_test.lua")  you will see that the result is OK, typing the right temperature, 29C in our case.

LM75 - I2C Communication - 500 us timebase

  If we zoom in a bit, we will be able to identify also our code snippets:
  
   i2c.start(bus)     
  i2c.address(bus, address, i2c.TRANSMITTER)
  i2c.write(bus, temp_reg)
  i2c.stop(bus)


-> address    = 0x48 
-> temp_reg = 0x00 

LM75 - I2C Communication - zoom in - 1


  i2c.start(bus)
  i2c.address(bus, address, i2c.RECEIVER)
  c=i2c.read(bus, 2)
  i2c.stop(bus)

  h,l = string.byte(c,1,2)

 - > h = 29 (0x1D)  
 - >  l = 0 (0x00)

LM75 - I2C Communication - zoom in - 2

 So, as you can see above, all OK and confirmed also by decoding the I2C communication on the Oscilloscope.

Now, let's see what's happening when running the same code  from the console (just select the code and press "Execute Selection" button.

-> h = 255
-> l = 255
-> temp = 0.5

WHAT?! WHY?!

Let's take a look on the Osciloscope also for this Run, using the same timebase, 500us :

LM 75 - I2C Communication - Run from console - 500us



Confused?  Let's increase the time base to 500ms and let's see what we can found about:

LM 75 - I2C Communication - Run from console - 500ms

What is telling us the last picture? The TIMING now is totally wrong !!

 Why?
 Because of the way that the code is sended to the interpreter and the way that is run, line by line!!

And please remember , these nasty things might happen in some conditions, even in case of a compiled code, not interpreted, when the code is in a step-by-step debugger mode run!

Might look silly and trivial, but imagine a way more complex code, all working OK, adding some extra modules, start debugging for them and suddenly starting having problems with previous tested modules, some nice working ones!
If you fall in such a trap, you can end up to spin around in circles for weeks.

What can be the solution? Easy. Just use the Rule number one: keep sensitive things like communication/timing and stuff at "atomic" level! Reading carefully the Datasheets can help you to quickly identify the "atomic granulation".

How can be done that in a easy way? Simple. Just use a FUNCTION!

Rememer, using functions in you code will give you not only the advantage of high readability, a modular and structural programming, easy debugging, etc,  but also, if functions are designed properly, can help you to avoid a potential pitfall as the one above.

Corrected code:

address = 0x48  -- LM75 I2C Address
temp_reg = 0     -- temp reg

bus = 0              -- I2C bus
sda, scl = 2, 1   -- Used pins for SDA and SCL
 

-- init I2C Bus  
   i2c.setup(bus, sda, scl, i2c.SLOW)
 

-- LM 75 Communication
function read_temp()
  i2c.start(bus)     
  i2c.address(bus, address, i2c.TRANSMITTER)
  i2c.write(bus, temp_reg)
  i2c.stop(bus)


  i2c.start(bus)
  i2c.address(bus, address, i2c.RECEIVER)
  c=i2c.read(bus, 2)
  i2c.stop(bus)

  h,l = string.byte(c,1,2)
  if h > 127 then h = h - 255 end       
  if l > 127 then l = 5 else l = 0 end  
  temp=string.format("%d.%d", h,l)
  print(temp)

end

read_temp()

And Yes, you can refine it even better than that :)

function init_I2C(sda, scl)
    i2c.setup(bus, sda, scl, i2c.SLOW)
end

function read_temp()
  i2c.start(bus)     
  i2c.address(bus, address, i2c.TRANSMITTER)
  i2c.write(bus, temp_reg)
  i2c.stop(bus)


  i2c.start(bus)
  i2c.address(bus, address, i2c.RECEIVER)
  c=i2c.read(bus, 2)
  i2c.stop(bus)
end 


function print_temp(c)
  h,l = string.byte(c,1,2)
  if h > 127 then h = h - 255 end       
  if l > 127 then l = 5 else l = 0 end  
  temp=string.format("%d.%d", h,l)
  print(temp)

end

-->>
init_I2C(sda, scl)
read_temp()
 print_temp(c)
 29.0