Barcode Scanner for Bring! Shopping List

6,813

57

16

Introduction: Barcode Scanner for Bring! Shopping List

This project aims to create a gadget that reads the 2D barcodes of the products I want to add to my shopping list. (Bring! Shopping List App).

The gadget is built with an M5StickC + a 2D barcode reader with a serial port (YK-E1005-OEM) + a box built with a 3D printer to integrate them.

To communicate with the Bring! application I took advantage of my Raspberry PI running Home Assistant. The barcodes are sent through MQTT to the MQTT server (Mosquitto) and once received in HomeAssistant a code programmed in Python is launched. This program looks for the barcode in an excel sheet where you can find the list of all the products. Once the product is identified it is sent to the Bring! application through an unofficial API and by MQTT the product name is returned to show it on the barcode reader screen.

Supplies

M5Stick C (10€)

CCD Barcode scanner 1D - 3,3Vcc (15€)

Ribbon cable to PCB board (5€)

Step 1: Schematics

Only four signals are required to connect the barcode reader to the ESP32 (M5StickC): Vcc, GND, TX and Trigger.

YK-E1005 <----- > M5StickC

Vcc <------> 3V3

GND <------> GND

TX <------> G36

Trigger <-------> G26

To make the connection I used an intermediate plate to avoid having to perform complicated soldering.

Step 2: Printing Case

The box is designed in Tinkercad and is a beta version. For now it is not the ideal box but for testing it is enough.

The base contains a connector with a magnet so you can quickly connect and disconnect the charger.

Step 3: Program M5StickC

To program the M5StickC I used the Arduino IDE using the basic libraries.

The operation is as follows:

-Once the A button is pressed the capture trigger of the reader is activated and it waits to receive data through the serial port for a maximum time of 10 seconds.

-When the information is received through the serial port, the barcode is sent to the MQTT server.

-If a product name is received from the MQTT server, it is shown on the screen.

-The display is turned off, in order not to damage it, when the charger is connected. The input voltage is checked.

//
// Lector codigo barras para M5Stack Stick-C
//
// Mayo-2020
//
// daekka LNX

#include <M5StickC.h>
#include <WiFi.h>
#include <PubSubClient.h>

//WiFi credentials
char* ssid       = "xxxxxx";
char* password   = "xxxxxx";
const char* mqtt_server = "192.168.1.200";
const char* mqttUser = "xxxxxx";
const char* mqttPassword = "xxxxxx";
WiFiClient espClient;
PubSubClient client(espClient);

// LED
#define ledPin 10
// Pin trigger lector
#define triggerPin 26

bool usb_power = false;
unsigned long previus_millis_captura = millis();
const int timeThreshold_captura = 10000;
String codigo_leido="";


// the setup routine runs once when M5StickC starts up
void setup() {

  // initialize the M5StickC object
  M5.begin();

  // Trigger del lector
  pinMode (triggerPin, OUTPUT);
  digitalWrite (triggerPin, HIGH);

  // LED
  pinMode (ledPin, OUTPUT);
  digitalWrite (ledPin, HIGH);  // turn off the LED

  // Puerto serie
  Serial2.begin(9600,SERIAL_8N1,36,0);

  // Activa el wifi y MQTT
  activa_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

  // Ajusto el brillo
  //M5.Lcd.setBrightness(80);

  // Rota la pantalla
  M5.Lcd.setRotation(3);
  M5.Axp.ScreenBreath(10);
  // Lcd display
  M5.Lcd.fillScreen(WHITE);
  delay(500);
  M5.Lcd.fillScreen(RED);
  delay(500);
  M5.Lcd.fillScreen(GREEN);
  delay(500);
  M5.Lcd.fillScreen(BLUE);
  delay(500);
  M5.Lcd.fillScreen(BLACK);
  delay(500);

  if (M5.Axp.GetVBusVoltage() > 4) {
    usb_power = false;
  }
  else {
    usb_power = true;
  }

}

void activa_wifi() {
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
}

void callback(char* topic, byte* message, unsigned int length) {
  String messageTemp;

  if (String(topic) == "lector_codigo_barras/in") {
      for (int i = 0; i < length; i++) {
        messageTemp += (char)message[i];
      }
      for (int i = 0; i < 10; i++) {
        messageTemp += " ";
      }
      display_producto (messageTemp);
  }
}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    // Attempt to connect
    if (client.connect("M5stickC-Codigo_barras")) {
      // Subscribe
      client.subscribe("lector_codigo_barras/in");
    } else {
      delay(1000);
    }
  }
}

void display_titulo (String titulo) {
  M5.Lcd.setTextColor(WHITE,BLACK);
  M5.Lcd.drawString(titulo + "              ", 11, 8, 1);

}
void display_producto (String producto){
  M5.Lcd.setTextColor(GREEN,BLACK);
  M5.Lcd.drawString(producto + "         ", 10, 30, 4);
}

void display_codigo_barras (String codigo) {
  M5.Lcd.setTextColor(RED,BLACK);
  M5.Lcd.drawString(codigo + "         ", 10, 60, 2);
}

void enciende_pantalla (){
  M5.Lcd.writecommand(ST7735_DISPON);
  M5.Axp.ScreenBreath(10);
  M5.Lcd.fillScreen(BLACK);
  display_titulo ("LECTOR CODIGO BARRAS");
  display_producto ("Producto.....");
  display_codigo_barras ("Esperando.....");
}

void apaga_pantalla (){
  M5.Lcd.writecommand(ST7735_DISPOFF);
  M5.Axp.ScreenBreath(0);
}

void comprobacion_usb_conectado() {
  // Apaga la pantalla
  if ((M5.Axp.GetVBusVoltage() > 4) && (usb_power == false) ){
      usb_power = true;
      apaga_pantalla();
  }
  if ((M5.Axp.GetVBusVoltage() <= 4) && (usb_power == true) ){
      usb_power = false;
      enciende_pantalla();
  }
}

void captura_codigo () {

     digitalWrite (ledPin, LOW);  // turn on the LED
     digitalWrite (triggerPin, LOW); // Activa lector
     previus_millis_captura = millis();
     while (Serial2.available() == 0 && (millis()-previus_millis_captura<timeThreshold_captura)) {
        delay (10);
     }

     if (millis()-previus_millis_captura<timeThreshold_captura) {
        M5.Lcd.fillScreen(GREEN);
        delay (100);
        codigo_leido = Serial2.readString();
        M5.Lcd.fillScreen(BLACK);
        M5.Axp.ScreenBreath(10);
        display_titulo ("LECTOR CODIGO BARRAS");
        int str_len = codigo_leido.length()-1;
        char char_array[str_len];
        codigo_leido.toCharArray(char_array, str_len);
        client.publish("lector_codigo_barras/out", char_array);
        display_codigo_barras (codigo_leido);
     }
     else {
        display_codigo_barras ("TIME OUT.....");
     }
     digitalWrite (triggerPin, HIGH); // Apaga lector
     digitalWrite (ledPin, HIGH);  // turn on the LED
}


// the loop routine runs over and over again forever
void loop(){

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

  // Comprueba si esta el USB cargador conectado y apaga o enciende la pantalla
  comprobacion_usb_conectado();
  // Actualiza estado botones
  M5.update();
  if (M5.BtnA.wasPressed()) {
      captura_codigo();
  }

}

Step 4: HomeAssistant

Integrations to be implemented:

-MQTT sensor: receives the barcode from the reader.

-Shell Command: executes the Python code

-Automation: launches the Python code once data is received at the MQTT sensor.

############################################################
#
# Home Assistant - Lector codigo de barras
#
############################################################
 
sensor:
  - platform: mqtt
    name: lector_codigo_barras 
    state_topic: "lector_codigo_barras/out"
    expire_after: 2
    
shell_command: 
    insert_producto_lector_codigo_barras: '/usr/bin/python /home/homeassistant/.homeassistant/python/bring/insert_producto_lector_codigo_barras.py "{{ producto }}"'
          
automation:
  - alias: recibido_codigo_barras
    initial_state: true
    trigger:
      - platform: state
        entity_id: sensor.lector_codigo_barras
    action:
      - service: shell_command.insert_producto_lector_codigo_barras
        data_template:
            producto: '{{ states.sensor.lector_codigo_barras.state }}'

Step 5: Python Script

The Python program does the following:

-Searches for the received code (sys.argv[1]) in the excel sheet where the products are stored.

-Sends by MQTT the name of the product.

-Add the product to the Bring! application using the unofficial BringApi library.

#!/usr/bin/env python
# coding: utf8

# Find barcodes from excel sheet
# daekka LNX

import requests
import json
import sys
import os
import xlrd
from collections import OrderedDict
import bringapi
import time

# Open the workbook and select the worksheet (first=0)
path_excel_productos = '/home/homeassistant/.homeassistant/python/bring'
file_name_excel_productos = 'barcode_productos.xlsx'
wb = xlrd.open_workbook(os.path.join(path_excel_productos, file_name_excel_productos))
sh = wb.sheet_by_index(0)

#Iterate through each row in worksheet and fetch values into dict
for rownum in range(1, sh.nrows):
    row_values = sh.row_values(rownum)
    if row_values[3] == sys.argv[1]:
       producto = OrderedDict()   
       producto['id_aleman'] = row_values[0]
       producto['id_traduccion'] = row_values[1]
       #producto['id_categoria'] = row_values[2]
       #producto['id_codigo'] = row_values[3]
       
       #MQTT
       os.system ('mosquitto_pub -h 192.168.1.200 -m "' + producto['id_traduccion'] +'" -t lector_codigo_barras/in')

       #BRING!
       bring = bringapi.BringApi("user","password",True)
       bring.purchase_item(producto['id_aleman'],"")

       #Finaliza buble
       break

The excel sheet has 4 columns:

1º Original name of the product in the application. This is the name to be used in the APIBRING so that no new products are created. If you use a name that is not in Bring! the product will be created and you will have to modify the category and the icon in the application.

2º Translation to my language. This is the name that I show in the M5Stick screen.

3º Category to which the product belongs (not used)

4º Bar code. When there are several brands of the same product, the row must be duplicated with the same data

Arduino Contest 2020

Participated in the
Arduino Contest 2020

1 Person Made This Project!

Recommendations

  • Backyard Contest

    Backyard Contest
  • Summer Fun: Student Design Challenge

    Summer Fun: Student Design Challenge
  • Fandom Contest

    Fandom Contest

16 Comments

0
BoeingBennie
BoeingBennie

Question 9 months ago

Nice Project. Thanks. Can I download the printfiles of the box for the 3D-printer?

0
bennyboom
bennyboom

8 months ago

Awesome project ! Good job!
What kind of charger are you using (when you say 'The base contains a connector with a magnet so you can quickly connect and disconnect the charger.' ? Are you talking about USB Type magnet connector ? if yes I see what it is ;) )
Thanks a lot

1
DavidE281
DavidE281

Reply 7 months ago

Yes, It is a magnet connector.

0
vincelaus
vincelaus

5 months ago

Hi

I'm trying to build your nice project but I have a problem to get it to connect with MQTT broker in hassio (you install it in supervisor) and that is already used by some other devices in my system but your code is unable to connect to it. I created a dedicated login/pass for it but no way. Broker gives me that in logs:

1612026186: New connection from 192.168.1.106 on port 1883.
1612026186: Socket error on client , disconnecting.

Any ideas what's the problem ? my broker runs with defaults options.

Thanks

Vincèn

0
DavidE281
DavidE281

Reply 5 months ago

Sorry, I have no idea.
I'll see how I have it configured and let you know.

0
Ajaxjones
Ajaxjones

1 year ago

Great project. I've just made this too, but I couldnt get the bar code reader to work in serial mode. I had to make it read factory bar codes to switch from USB into serial. Did you have to do the same, or did yours come as serial as default? Did you test it prior and send it serial on the Rx perhaps as I am wondering if that is a way to get it to switch?

0
DavidE281
DavidE281

Reply 1 year ago

My reader is configured as a serial reader by default. I didn't have to do or configure anything.

0
luklev
luklev

1 year ago

Nice project :)

0
Patave
Patave

Question 1 year ago on Step 5

Hi, very interesting project.
I want to test the bringApi, but I have an error message.
I had install python3 and BringAPI librairy
I extracted from your code the only 2 lines for Bring! in a Python File bring.py

Result:
File "bring.py", line 18
bring = bringapi.BringApi("user","password",True)
^
IndentationError: unexpected indent

Could you help me?

0
Patave
Patave

Answer 1 year ago

Sorry I found my problem of indentation.
but I have a new error:
My python code:
#!/usr/bin/env python
# coding: utf8
import requests
import BringApi
#BRING!
bring = BringApi.BringApi("user","password",True)
bring.purchase_item("Wasser","")

And the result:
(my_env) patrick@alderaan:~/environments$ python3 bring.py
Traceback (most recent call last):
File "bring.py", line 15, in <module>
bring = BringApi.BringApi("user","password",True)
AttributeError: module 'BringApi' has no attribute 'BringApi'

0
Patave
Patave

Reply 1 year ago

I have found the problem. Bad version of Python. 3.6 minimum

0
DavidE281
DavidE281

Reply 1 year ago

👌

0
schaapkameel
schaapkameel

1 year ago

Thats a cool project! thanks for sharing!

0
DavidE281
DavidE281

Reply 1 year ago

Thank you very much!
If you have any suggestions for improvement you can comment on them to see if I can implement them.