Showing posts with label lifehack. Show all posts
Showing posts with label lifehack. Show all posts

Wednesday, March 16, 2016

NodeMCU for the Absolute Beginner - Lessons Learned

About a year ago, a buddy of mine who knew I was really into Raspberry Pi and Arduino encouraged me to look into NodeMCU. It's an IoT hardware platform with an onboard Wifi chip as well as a linux-based OS which is programmable in Lua. I messed around with it long enough to see it connect to the web and download a test page from Adafruit, but honestly? I was starting my own business and absolutely swamped.

Fast forward a year. A long year. A year of almost no hacking - Arduino, Pi, nothing... On a whim, I broke out my Pi and started messing with the GPIO interface and soon had a BMP085 sensor connected to a Python script, writing temp data into a csv file. Pretty cool! Not included to quit while I'm ahead, and finding myself waiting on a couple of clients (and therefore with some 'flexible' time), I decided to break out the NodeMCU. Turns out, someone had gotten the BMP085 working on NodeMCU. After several hours across a couple of days, and running into a steep learning curve, I finally got my BMP085 working on NodeMCU as well!

NodeMCU - This Ain't a Piece of Pi (or Arduino)

OK so you want to jump aboard the IoT craze and get involved. You're familiar with Arduino but you want something lighter, faster, and network enabled. That fancy NodeMCU dev board has been calling you, right?

All in all, it's a nifty idea and it works well (once you get past the learning curve). But if you're coming in from Visual Studio, from Xcode or even from Arduino Studio, be warned: this is not a polished experience. In fact, it's pretty ugly and dirty. Lots of flashing, formatting, serial communications await you before you actually have a working application. It is definitely not for the faint of heart, but if you persist, you'll get there.

Not a Tutorial

This article isn't a tutorial, per say, but a collection of things I picked up over the past few days. Really, there are 3-4 'gotchas' that I'm going to document. There are plenty of tutorials out there, but many of them skip over the 'what the heck do I do now' scenarios. Hopefully I can fill in the gap for you a bit:
  • Flashing can be tricky. Use Windows.
  • Establish a serial connection as the Node device powers up, so you can see any error messages.
  • Debugging is a pain - you need to check for messages as soon as the device boots.

Flashing

I did most of my work on my Raspberry Pi--not really sure why except that it's a throw-away environment where I'm always in screen or minicom, so I wasn't overly concerned about messing things up, and I had all the tools I needed. It might be faster to work elsewhere (I'm running a Pi 3 B+ so it's actually not heinous). There's even a fancy flashing tool (esptool) available for Linux. However... don't do it. I ran into a really weird issue where I saw symptoms like:
  • Device showed up online, but worked 'wonky'
  • I could program it in Arduino studio with the NodeMCU plug in
  • I could not connect to it on Linux over serial comm, unless I tried 115200, but even then things were just weird.
I tried refreshing it with the esptool, which appeared to succeed, but which in the end actually failed.

The answer? Use the Windows flasher tool to flash the build. I spent a good 2 hours one evening digging around trying everything I could think of and finally powered up a Windows machine, flashed it and <poof> everything worked great.

Don't. Seriously, just don't flash it on Linux. Use Windows. It's worth the time you'll save.

Establish Serial Quickly

When the NodeMCU powers up, it very quickly spits some diagnostics to the serial port. It's important that you catch those diagnostics, to be sure you see any messages that might crop up, oh, if your code has a syntax error or such. There is NO INTELLISENSE and NO DEBUGGING on this platform. If you write a mistake, you're not going to catch it any other way besides 1) manual code review or 2) catching the Node as it boots. So be quick on the "screen /dev/ttyUSB0 9600" command, as soon as that device boots.

Debugging

I said it above, but... I created a web page to serve up my inside temp information. I had some syntax errors on the page (not surprising, since I was editing in Leafpad and had some rather convoluted HTML code). I tried three ways from Sunday to get the thing to run. I rebooted it 15 times, but each time I tried to connect, Safari or Android Chrome responded with a connection reset error. I could ping the device (and get responses), but it just wouldn't serve a page.

So then I remembered my point about establishing serial quickly. The next time I powered up, I opened up a serial console ASAP and sure enough - the device spat out some error message about malformed HTML. Fixed it and I was good to go, but I lost a couple hours on this.

Conclusion

I see a lot of great uses for the NodeMCU devices. Remote weather stations no longer need wires. You can put moisture sensors in the far corners of your damp basement. I'm even planning to use one for model rocket telemetry information. It's really a clever device, and the Lua language is rather fun to use. This is going to be a fun device in my arsenal. Keep an eye, by the way, at my other blog securitygeezer.blogspot.comsecuritygeezer.blogspot.com because I have a feeling the NodeMCU device is going to come in handy on penetration tests and such.

Sunday, August 24, 2014

Arduino: TempLogger

I’ve gotten terrible sleep the past 4-5 weeks. I wake up every night around 2 am, just hot and uncomfortable. I usually can’t get back to sleep once I wake up, either.

So time for another lifehack! I have an Arduino, I have an SD card logging shield, and I have a digital temp sensor – I decided to build a temperature logger and record the temps overnight.

WP_20140824_001[1]

Below is the code from my first attempt about a year ago. I broke it out again today and was looking at it – I found an article on the BMP085 online at Sparkfun, which when reading seems to indicate that you need to do a fair amount of calibration at startup in order to get accurate data. I went ahead and downloaded Sparkfun’s code and ran it – lo and behold, with all of its calculations it is still reporting the same 80 degrees my simple code is reading.

Lesson: you don’t need that calculation!

#include <Wire.h>
#include <Adafruit_BMP085.h>
#include <SD.h>
#include "Arduino.h"
#include "RTClib.h"

/**********************************************************************************
   TempLogger is an Arduino tool to log temperatures throughout a sustained time
   period. Ever wonder how well your heat is regulated? Tired of waking up hot at
   night? That's why I built templogger - my bedroom seemed awfully hot around 2
   am and, coincidentally, I kept waking up at 2 am.
  
   Requires an Arduino board, a GPS logging shield, and a BMP085 pressure/temp
   sensor from AdaFruit (
https://www.adafruit.com/products/391)
  
   See K7JTO.blogspot.com for this and other Arduino recipes.
**********************************************************************************/

/*
  Connect VCC - 3v
  Connect SCL - Analog pin #5
  Connect SDA - Analog pin #4
  Connect GND - GND (obviously)
*/

// Define Section
#define DEBUG 1                                    // Toggle 1/0 to en/disable serial out
#define led1Pin 5                                  // OPTIONAL: wire pin 5 to write LED
#define led2Pin 6                                  // OPTIONAL: wire pin 6 to read LED
#define BUFFSIZE 90                               // Create a buffer to store log file name

// Variables and Objects
Adafruit_BMP085 bmp;                                // ID for BMP085 unit
RTC_DS1307 RTC;                                     // Real-time clock object
const int chipSelect = 10;                          // Must be left as an output or SD library won't work
boolean gotSDCard = false;                          // Set to true if file successfully created
File logFile;                                       // File for logging data
char buffer[BUFFSIZE];                         // String buffer for the sentence
uint8_t i;                                          // usigned int for iterating
float currTemp = 0;                                 // Int for current temperature
String stringTemp = "";                             // String to hold temperature in
static char sprintfbuffer[15];                      // Buffer to convert float to string
static char dtostrfbuffer[15];                      // 2nd buffer to convert float to string

 

void setup() {
  Serial.begin(9600);
  if (!bmp.begin()) {
    Serial.println("Could not find a valid BMP085 sensor, check wiring!");
      return;
  }

  // Setting up the card means creating a new logging file for
  // each session, and initializing that logging file.
  if (setupSDCard()) {
    if (DEBUG) {
      Serial.println("card initialized.");
    }
    // Start RTC
    RTC.begin();
  }
}
 
void loop() {
  // Variables
  String nowTime = "";                                // String name for current time
  String dataString = "";                             // Store line for temp sensor
   
  // First grab the time from the RCT on the logging shield
  DateTime now = RTC.now();
 
  // Now build the timestamp. Should look like 12/25/2013 04:27:00"
  // Slight hack - sometimes the seconds value reads funny, and for
  // what we're doing, seconds aren't important, so just shove two
  // 0's in.
  nowTime += now.month(), DEC;
  nowTime += "/";
  nowTime += now.day(), DEC;
  nowTime += "/";
  nowTime += now.year(), DEC;
  nowTime += " ";
  nowTime += now.hour(), DEC;
  nowTime += ":";
  nowTime += now.minute(), DEC;
  nowTime += ":00";
 
  // Next grab the temp from the BMP. Problem is the temp comes in as an int, which
  // the Arduino can't convert to a string. So once the temp comes in, turn it into
  // a string via sprintf and dtostrf
  currTemp = ((bmp.readTemperature()*1.8)+32);
  sprintf(sprintfbuffer,"%f", currTemp);
  dtostrf(currTemp,8, 2, dtostrfbuffer);
 
  dataString = nowTime + "," + dtostrfbuffer;
  if(DEBUG) {
    Serial.println("Datastring: ") + dataString;
  }
   
  // Now write temp to logfile
  File dataFile = SD.open(buffer, FILE_WRITE);
   
    // if the file is available, write to it:
    if (dataFile) {
      // Light an LED
      digitalWrite(led1Pin, HIGH);
      digitalWrite(led2Pin, HIGH);
     
      // Write
      dataFile.println(dataString);
      dataFile.close();
     
      // Unlight the LED
      delay(1000);
      digitalWrite(led1Pin, LOW);
      digitalWrite(led2Pin, LOW);
     
      // print to serial port too:
      if (DEBUG) {
        Serial.println(dataString + " saved to data file");
      }
    }
    else {
      Serial.println("Error opening log file to write " + dataString);
    }
   
   // Now delay the device. This could be a sleep delay, if the device were running off
   // batteries, but a simple delay will suffice for externally-powered scenarios.
    delay(60000);
}

//** Sets up SD card. Returns true if no error **/
boolean setupSDCard() {
  // Now set up SD for logging
  // This code lifted from "Datalogger" sample sketch
  if (DEBUG)
    Serial.println("Initializing SD card...");
// make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);
// see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card init. failed! chipSelect = " + chipSelect);
    error(1);
    return false;
  }
  // Now create a unique file. NOTE: IF YOU CHANGE THE FILE NAME, CHECK THAT YOUR INDEXES STILL WORK
  // (buffer[6] and buffer[7] will need to change if you change the length of the file name)
  strcpy(buffer, "TMPLOG00.TXT");
  for (i = 0; i < 100; i++) {         
    // Keep iterating till you find unique file name
    // Create if does not exist, do not open existing, write, sync after write
    buffer[6] = '0' + i/10;
    buffer[7] = '0' + i%10;
    if (! SD.exists(buffer)) {
      break;
    }
  }
  // Now open the file just created
  logFile = SD.open(buffer, FILE_WRITE);
  if( ! logFile ) {
    if (DEBUG)
    {
       Serial.print("Couldnt create "); Serial.println(buffer);
    }
    error(3);
    return false;
  }
  if (DEBUG)
  {
    Serial.print("Creating file on card: "); Serial.println(buffer);
  }
  return true;
  // Done opening log file
}

// Handling Errrs HERE
// blink out an error code
void error(uint8_t errno) {
  if (DEBUG)
  {
     Serial.print("Error encountered. Error no: ");
     Serial.print(errno);
  }
 
  // First, blink 3x fast
  blinkThrice();
 
  // Now blink errno times, slow
  for (i=0; i<=errno; i++) {
    digitalWrite(led1Pin, HIGH);
    digitalWrite(led2Pin, HIGH);
    delay(3000);
    digitalWrite(led1Pin, LOW);
    digitalWrite(led2Pin, LOW);
    delay(1000);
  }
 
  blinkThrice();
}

void blinkThrice() {
  for (i=0; i<3; i++) {
    digitalWrite(led1Pin, HIGH);
    digitalWrite(led2Pin, HIGH);
    delay(3000);
    digitalWrite(led1Pin, LOW);
    digitalWrite(led2Pin, LOW);
    delay(1000);
  }
}

/***************************************************
  Portions of this code based on Adafruit BMP085 sample code. See
  info below.

  Designed specifically to work with the Adafruit BMP085 Breakout
  ---->
https://www.adafruit.com/products/391

  These displays use I2C to communicate, 2 pins are required to interface
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries. 
  BSD license, all text above must be included in any redistribution
****************************************************/

Sunday, March 10, 2013

TrunkTrackerino

It's simple, really:
I have teens...
They drive my car...
They are boys...
I am an engineer...
I like life hacks...
I have an Arduino...
And a GPS logging shield....

Therefore, TrunkTrackerino.

More than two years ago I started a push to get my Arduino working with the GPS logger shield. It failed, mostly because I had some other life pressures. I recently pulled out my Arduino and started messing with it again, not really sure why... And I got the GPS working. And then I thought... I can build a simple device to throw in the trunk that will record driving speed! And thus TrunkTrackerino was born.

There are sketches for using a GPS. There are also sketches for logging GPS data to a card reader. But I really didn't like any of them individually, so I have merged them together. And as of today, I believe I have it working (not entirely sure, since I'm in my hotel and can't pick up signal--I will know more tomorrow).

The goal is to build an Arduino-based device which
* tracks speed and location
* sleeps when there is no motion
* logs nothing when there's no valid data
* stores data on an SD card
* can be imported into XL to view historical speed data
* can be imported into Google Earth for bread crumb data

Eventually this project will end up as the base for the APRS balloon tracking system. For now, it's enough to know my boys are as honest as they say they are.

Update: I took a brief stroll around the hotel entrance today. For some reason, the logging code is logging an empty file. The GPS is working great--when I watch in Arduino's serial monitor, I can see good valid strings which are being parsed great. I'd say I'm 10 lines of code from a working beta.