Close

LameBoy MQTT pager aka LameQuix [by @woodworker]

A project log for LAMEBOY - another ESP12 handheld

fully portable ESP12 project with battery charging and power muxing

woodworkerWooDWorkeR 03/17/2018 at 23:525 Comments

The Idea

I've wanted to build myself a small MQTT based message reader like those majestic 90s pagers everybody lusted after back then and I have a Lameboy.
So I knew what i had to do.

This "mod" does consist of 2 parts, a little hardware upgrade and a very small firmware.

The Hardware

All we need is an NPN-transistor and a small vibration motor (+ something to glue it to the Lameboy)

The Lameboy has 2 visible Action Buttons, the A and B button. But there is also a C button hidden on the backside/inside of your little Lameboy and thanks
to the magic of the I/O expander used, this button will be an OUTPUT!!!!

We add an NPN Transistor with its base connected to the C-Button pad, collector to 3.3V and the emitter to the positive side of our vibration motor. And the negative side of the motor we just solder to ground.

The Software

/**
 *  _                           ____        _      
 * | |                         / __ \      (_)     
 * | |     __ _ _ __ ___   ___| |  | |_   _ ___  __
 * | |    / _` | '_ ` _ \ / _ \ |  | | | | | \ \/ /
 * | |___| (_| | | | | | |  __/ |__| | |_| | |>  < 
 * |______\__,_|_| |_| |_|\___|\___\_\\__,_|_/_/\_\
 */

#include <ESP8266WiFi.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <Wire.h>
#include <PubSubClient.h>

uint32_t bat = 4200;
Adafruit_PCD8544 display = Adafruit_PCD8544(2, 15, 0);

#define BUTTON_UP    B10000000
#define BUTTON_DOWN  B00100000
#define BUTTON_LEFT  B01000000
#define BUTTON_RIGHT B00010000
#define BUTTON_B     B00000100
#define BUTTON_A     B00001000
#define BUTTON_SD    B00000010

#define MESSAGE_LENGTH    100
#define MAX_MESSAGES        4

boolean bottonU_pressed = false;
boolean bottonD_pressed = false;
boolean bottonL_pressed = false;
boolean bottonR_pressed = false;
boolean bottonA_pressed = false;
boolean bottonB_pressed = false;
boolean bottonSD_pressed = false;

boolean bottonU_last_pressed = false;
boolean bottonD_last_pressed = false;
boolean bottonL_last_pressed = false;
boolean bottonR_last_pressed = false;
boolean bottonA_last_pressed = false;
boolean bottonB_last_pressed = false;
boolean bottonSD_last_pressed = false;

boolean bottonU_changed = false;
boolean bottonD_changed = false;
boolean bottonL_changed = false;
boolean bottonR_changed = false;
boolean bottonA_changed = false;
boolean bottonB_changed = false;
boolean bottonSD_changed = false;

const char* ssid = "YOUR_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* mqtt_server = "your.mqtt.server";

const char* readChannel = "inTopic";
const char* writeChannel = "outTopic";

WiFiClient espClient;
PubSubClient client(espClient);

char msg[100];

long lastMsg = 0;
int showMessage = 0;
int messageCount = 0;
char lastmsg[MAX_MESSAGES][MESSAGE_LENGTH];

bool hasMessage = false;
bool hasRead = true;

int value = 0;

void setup()
{
  Serial.begin(115200);
  Wire.begin();

  Wire.beginTransmission(0x38);
  Wire.write(B11111110);
  Wire.endTransmission();

  setBackgroundColor('c', 200,200,200);

  display.begin();
  display.clearDisplay();
  display.setRotation(2);
  display.setContrast(58);
  display.display();

  setBackgroundColor('n', 255, 100, 100);
  display.clearDisplay();
  display.setCursor(0, 0);
  display.setTextSize(2);
  display.setTextColor(BLACK);
  display.println("OH HI!");
  display.display();
  delay(2000);

  display.setTextColor(BLACK, WHITE);
  display.setTextSize(1);

  setup_wifi();
  
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");

  if (messageCount < MAX_MESSAGES) {
    messageCount++;
  }

  ///// lastmsg buffer change
  for (int k = MAX_MESSAGES - 1; k > 0; k--) {
    for(int l = 0; l < MESSAGE_LENGTH; l++) {
      lastmsg[k][l] = lastmsg[k-1][l];
    }
  }

  for(int j = 0; j < MESSAGE_LENGTH; j++) {
    lastmsg[0][j] = NULL;
  }
  
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    if (i < MESSAGE_LENGTH) {
      lastmsg[0][i] = (char)payload[i];
    }
  }
  hasMessage = true;
  hasRead = false;
  showMessage = 0;
  Serial.println();
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect("ESP8266Client")) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish(writeChannel, "hello world");
      // ... and resubscribe
      client.subscribe(readChannel);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void loop() 
{
  read_buttons();
  
  display.clearDisplay();

  // show selected message
  display.print("Msg #");
  display.print((showMessage + 1));
  display.print("/");
  display.print(messageCount);
  
  // show battery voltage
  uint32_t aIn = analogRead(A0);
  aIn = map(aIn, 0, 1024, 0, 4400); 
  bat = (aIn+bat)/2;
  display.print("  ");
  display.println(bat);

  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  // print selected message
  display.print(lastmsg[showMessage]);
  display.println("");

  // backlight on in case of unread message
  if (hasRead) {
    setBackgroundColor('n', 0, 0, 0);
  } else {
    setBackgroundColor('n', 255, 100, 100);
  }

  // notify for new message
  if (hasMessage) {
    vibrate(200);
    hasMessage = false;
  }

  // scroll messages down
  if (bottonD_pressed && bottonD_changed) {
    if (showMessage < ( MAX_MESSAGES - 1) ) {
      showMessage++;
    }
  }

  // scroll messages up
  if (bottonU_pressed && bottonU_changed) {
    if (showMessage > 0) {
      showMessage--;
    }
  }
  
  // mark message read
  if (bottonB_pressed) {
    if (showMessage == 0) {
      hasRead = true;
    }
  }

  // send message
  if (bottonA_pressed && bottonA_changed) {
    ++value;
    snprintf (msg, 75, "hello world #%ld", value);
    Serial.print("Publish message: ");
    Serial.println(msg);
    client.publish(writeChannel, msg);
    vibrate(100);
  }
  
  display.display();
  delay(100);
}

void vibrate(int milli) {
    Wire.beginTransmission(0x38);
    Wire.write(B11111111);
    Wire.endTransmission();

    delay (milli);
    
    Wire.beginTransmission(0x38);
    Wire.write(B11111110);
    Wire.endTransmission();
}

void setBackgroundColor(char c, int r, int g, int b)
{
  // c is fade to color, n is now color
  Wire.beginTransmission(0x80);
  Wire.write(c);
  Wire.write(r);
  Wire.write(g);
  Wire.write(b);
  Wire.endTransmission();
}

void read_buttons()
{
  Wire.requestFrom(0x38, 1);
  byte data = Wire.read();
  bottonU_pressed = (~data & BUTTON_UP) > 0;
  bottonD_pressed = (~data & BUTTON_DOWN) > 0;
  bottonL_pressed = (~data & BUTTON_LEFT) > 0;
  bottonR_pressed = (~data & BUTTON_RIGHT) > 0;
  bottonA_pressed = (~data & BUTTON_A) > 0;
  bottonB_pressed = (~data & BUTTON_B) > 0;
  bottonSD_pressed = (~data & BUTTON_SD) > 0;

  bottonU_changed = bottonU_last_pressed != bottonU_pressed;
  bottonD_changed = bottonD_last_pressed != bottonD_pressed;
  bottonL_changed = bottonL_last_pressed != bottonL_pressed;
  bottonR_changed = bottonR_last_pressed != bottonR_pressed;
  bottonA_changed = bottonA_last_pressed != bottonA_pressed;
  bottonB_changed = bottonB_last_pressed != bottonB_pressed;
  bottonSD_changed = bottonSD_last_pressed != bottonSD_pressed;
  
  bottonU_last_pressed = bottonU_pressed;
  bottonD_last_pressed = bottonD_pressed;
  bottonL_last_pressed = bottonL_pressed;
  bottonR_last_pressed = bottonR_pressed;
  bottonA_last_pressed = bottonA_pressed;
  bottonB_last_pressed = bottonB_pressed;
  bottonSD_last_pressed = bottonSD_pressed;
}

Now i have my very own small and simple MQTT based pager \o/

Discussions

davedarko wrote 08/22/2019 at 11:43 point

for later: https://www.adafruit.com/product/1201

Dimension: 10mm diameter, 2.7mm thick
Voltage: 2V - 5V
5V current draw: 100mA, 4V current draw: 80mA, 3V current draw: 60mA, 2V current draw: 40mA
11000 RPM at 5V
Weight: 0.9 gram

  Are you sure? yes | no

WooDWorkeR wrote 03/18/2018 at 15:19 point

i created a github repository for this project

https://github.com/woodworker/lamequix

  Are you sure? yes | no

Craig Hissett wrote 03/18/2018 at 00:07 point

Awesome update buddy!

  Are you sure? yes | no

davedarko wrote 03/18/2018 at 00:08 point

@woodworker did a great job on his lameboy :)

  Are you sure? yes | no

Craig Hissett wrote 03/18/2018 at 00:18 point

He certainly did! I'd love to use one as a little handheld controller for my son's tank robot. A Nodemcu is running a webserver to control it at the moment but this would make a great little remote for him. The messaging feature of the pager would come in handy too :-)

  Are you sure? yes | no