Gibt es für HA einen Barcode-scanner (evtl. mit ESP32)

und eine Integration dazu?
ich möchte meine Einkaufsliste automatisch befüllen …

der Scanner sollte über WiFi oder zigbee funktionieren und
sollte automatisch (also ohne immer extra einen Knopf drücken zu müssen) einen Artikel erkennen …

Einbauposition kann ich mir zB neben dem Mülleimer in der Küche vorstellen

dieses Video kenne ich bereits …

scheint aber alles noch ein Prototyp zu sein und wenn es was fertiges gibt (ohne Bastelei) wäre mir das auch lieber.

Moin,

ich bin der Meinung mal etwas gelesen zu haben, das man das auch mit Handy und APP hinbekommt, muss aber erst mal suchen gehen.

Einmal das, mit der Companion APP

Falls Du mal Grocery testen möchtest

VG
Bernd

mit der companion app als ersten Test wäre schön aber Dein Link #1 ist ein feature request, die app kann das bisher nicht.

aber wie ich gerade gesehen habe, sind die Bauteile für den Scanner aus dem Video oben viel günstiger geworden, inzwischen vermutlich < €20. Man muss sich natürlich noch die PCB bestellen …

EDIT:

und das werde ich jetzt mal machen, habe dann am Ende 4 Stk. davon übrig.

Wer interessiert ist, bitte PN ….

Ich habe es auch schon versucht umzusetzen, bin aber gescheitert. Lass uns gerne zusammen daran arbeiten.

aber gerne doch …

demnach hast Du die Bauteile aus meinem ersten Video evtl. schon gekauft?

vielleicht hast Du sogar eine PCB übrig?

Ne, noch nicht. Ich hoffte, dass ich das mit einem Barcode Scanner am Handy umsetzten kann.
Ich habe dir eine PM gesendet.

Barcodescanner am Handy ist für einen Test ok aber mE nicht alltagstauglich.

Das Handy muss immer erst gesucht, eingeschaltet, App gestartet und eingescannt werden.

ich habe auch noch keine App gefunden, die das macht und das Ergebnis an HA übergibt.

Die Lösung von Daniel Scheidler erscheint mir am Ende besser ….

EDIT:

Da ich an der Hardware im Urlaub nichts machen kann, habe ich mich etwas mit der Software/Automation beschäftigt. Folgende Probleme könnten auftreten:

  1. Der barcode-scanner liefert zB sowas als Ergebnis:

    Würze flüssig 250 gr Flasche – MAGGI – 202ml

    ich will aber nur “MAGGI” auf der Einkaufsliste stehen haben

  2. wenn eine leere Verpackung zB Kaffee in den Müll wandert ist der Kaffee ja komplett verbraucht und wenn ich keinen Ersatz habe, hätte ich am nächsten Morgen keinen Kaffee oder man geht sofort einkaufen (macht aber keiner)

Ja…da hab ich auch schon mal Gehirmschmalz reingesteckt, rausgekommen ist dabei sowas:


In der Küche werden Produkte erfasst die wenn sie leer sind neu gekauft werden sollen, trifft ja nicht immer auf alles zu…


Im Vorratslager werden alle Produkte gescannt die reingehen oder rausgenommen werden. Dort ist aber auch nur das Lager-Zeugs inventarisiert, nicht sowas wie Butter oder Milch oder so, das landet ja gleich im Kühlschrank und wird erfasst wenn es nachgekauft werden soll.

Das ganze basiert auf ESPHome mit einem Barcodescanner und übermittelt alles via API an Grocy was in einem Docker läuft (ist zuverlässiger als die Add-On Version in HA)

Derzeit baue ich noch ein das alles was den Mindestbestand unterschreitet automatisch auf der Einkaufsliste landet, das hilft vorallem meiner Frau nicht Dinge zu kaufen die wir noch ausreichend da haben :rofl:

3 „Gefällt mir“

coole Sache, genau sowas schwebt mir auch vor und auf die Idee hat mich eigentlich die Einkaufsliste gebracht. Die läuft aktuell bei uns mit der Bring! App und ich struggle immer noch an der Automation, die ein eingekauftes Item registriert und darauf reagiert.

einfaches Beispiel für ein usecase: die Geschirrtabs.
da wird ein Zähler von 60 (so viele Taps sind in einer Packung) heruntergezählt jedes mal wenn die Spülmaschine gelaufen ist. Bei down to 7 kommen die Tabs automatisch auf die Einkaufsliste. Das funktioniert bereits.
Wenn die Tabs dann eingekauft und auf der Liste abgehackt wurden, soll der Zähler wieder auf +60 gesetzt werden. Das funktioniert noch nicht. Die Bring! Integration stellt keine verwendbare Entität zur Verfügung (oder ich übersehe etwas).

analog kann man das leicht mit Batterien machen, die leer werden, dazu das add-on Battery-Notes verwenden

Grocy habe ich mir mal kurz angeschaut (als docker auf meinem unraid server) aber das war mir erstmal zu aufgebläht …

Aktuell beschäftige ich mich ja noch mit der Hardware. Hast Du den Scanner von Daniel (siehe YT aus erstem Post) verwendet?

Daniels Projekt war die Inspiration das es funktionieren kann. Ich hab das Teil genommen

Da nutze ich die UART Debug Funktion um die Barcodes an Grocy durchzureichen. Aber letztendlich musste ich alles selbstbauen da in den Food-Portalen so gut wie keine Schweizer Produkte zu finden sind. Deswegen geht alles ins Grocy und über eine Automation dann auch in die HA-Einkaufsliste. Ich hab die Produkte mit ihren teilweise mehreren Barcodes manuell ins Grocy eingepflegt. Glücklicherweise hat der Supermarkt unseres Vertrauens ein eigenes Wiki mit allen Produkten so das fast nur Copy-Paste war, kann man sich auch seinen letzten Bon anzeigen lassen, dann muss man in dem Wiki nicht suchen sondern hat schnell neue noch nicht eingepflegte Produkte oder Barcodes nachgepflegt.
Die haben auch ne API, aber da die nicht offiziell ist, gibts kaum ne Doku dazu.

ist der von dir verwendete scanner nicht dasselbe wie dieser von AliExpress
GROW GM60-S Anel de luz indicadora pode controlado pequena interface UART redonda 1D/2D Código de barras QR Code Módulo leitor de código de barras - AliExpress 7..

würdest Du mir einen Denkanstoß geben für eine Automation, wenn etwas auf der Einkaufsliste abgehackt wird, bitte.

Ich verwende zZt diese …

alias: Tabs_ok
description: Geschirrtabs gekauft und Bestand um +60 erhöht
triggers:
  - trigger: event
    event_type: call_service
    event_data:
      domain: todo
conditions:
  - condition: template
    value_template: "{{ trigger.event.data.service_data.entity_id == ['todo.einkaufen'] }}"
  - condition: template
    value_template: "{{ trigger.event.data.service_data.rename == 'Geschirrtabs' }}"
  - condition: template
    value_template: "{{ trigger.event.data.service == 'update_item' }}"
  - condition: template
    value_template: "{{ trigger.event.data.service_data.status == 'completed' }}"
    enabled: true
actions:
  - action: notify.persistent_notification
    metadata: {}
    data:
      message: Ausgelöst durch HA todo Liste
mode: single

das funktioniert aber nur, wenn man es auf der todo-Liste von HA abhackt, nicht wenn man dasselbe in der Bring! App macht (obwohl die Listen ständig synchronisiert werden) Hab den Fehler noch nicht gefunden …

EDIT:
würde auch ein GM861S UART Scanner funktionieren, so wie dieser …
GM861S UART

oder muß es ein GS60 sein?

Wahrscheinlich kannst du jeden Scanner nehmen, Hauptsache er liest EAN13 Codes und kann via UART oder I2C angesprochen werden.

das trifft beides auf den GS861S aus meinem Link zu …
und hier das ganze noch einen Tick günstiger

ich habe jetzt aus der Bestellung bei PCBway noch Platinen übrig, wer daran interessiert ist bitte eine PN.

1 „Gefällt mir“

Wie ist denn der aktuelle Stand? Habe nun den Code von @Smarthomeyourself mehrfach durch ChatGPT gejagt und jetzt läuft zumindest das Display korrekt aber wenn ich Produkte davor halte passiert nichts. Hat jemand hier ne funktionierende yaml mit der der Barcode Scanner in der aktuellen esphome version nutzbar wäre? LG

danke, das Du es nochmals anstösst, habe die Sache jetzt erstmal liegen galassen aber auf
discord hat sich ja einiges getan, muß ich alles mal nachlesen.
Wärst Du evtl. so nett, Deinen aktuellen yaml hier hochzuladen, dann muß ich nicht alles wieder durchsuchen und könnte auch schnell mal testen.
und mit welcher ESPhome Version hast Du kompiliert?
Ürigends:
Damit das Display richtig herum anzeigt nur diese Zeile einfügen …

display:
  - platform: ssd1306_i2c
    ...  
    rotation: 180

Hey… Ja das mit dem Display drehen habe ich bei mir auch drin.

Hier meine yaml mit der aktuellsten ESPHome Version validiert und geflasht.

esphome:
  name: barcode-scanner
  friendly_name: Barcode-Scanner

  on_boot:
    priority: 600
    then:
      - script.execute: init_display

substitutions:
  rest_opentindb_queryid: "400000000"

  display_i2c_sda: GPIO21
  display_i2c_scl: GPIO22
  ssd1306_i2c_address: 0x3C

  uart_tx_pin: GPIO09
  uart_rx_pin: GPIO10
  beeper_pin: GPIO16

esp32:
  board: esp32dev
  framework:
    type: arduino

logger:
  level: DEBUG
  baud_rate: 0  # Disable UART logging

api:
  encryption:
    key: "xxx"

ota:
  - platform: esphome
    password: "xxx"

wifi:
  ssid: !secret wifi_ssid2
  password: !secret wifi_password2

  manual_ip:
    static_ip: 192.168.20.65   # gewünschte feste IP
    gateway: 192.168.20.1      # IP deines Routers
    subnet: 255.255.255.0
    # optional:
    dns1: 192.168.20.1

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Barcode-Scanner Fallback Hotspot"
    password: "xxx"

# ---- Globale Variablen ----
globals:
  - id: xpos_ean
    type: int
    initial_value: "0"
  - id: xpos_brand
    type: int
    initial_value: "0"
  - id: xpos_prod
    type: int
    initial_value: "0"

# ---- UART Barcode Scanner ----
uart:
  id: uart_scan
  rx_pin: ${uart_rx_pin}   # GPIO09
  tx_pin: ${uart_tx_pin}   # GPIO10
  baud_rate: 9600
  debug:
    direction: RX
    dummy_receiver: true
    after:
      delimiter: "\r\n"
    sequence:
      - lambda: |-
          std::string barcode_str(bytes.begin(), bytes.end());
          barcode_str.erase(std::remove_if(barcode_str.begin(), barcode_str.end(), ::isspace), barcode_str.end());
          if (barcode_str.length() > 0) {
            ESP_LOGI("barcode", "Barcode empfangen: %s", barcode_str.c_str());
            id(barcode_scanner).publish_state(barcode_str);
          }

# ---- Textsensoren ----
text_sensor:
  - platform: template
    id: barcode_scanner
    name: "${friendly_name} Scan"
    on_value:
      then:
        - script.execute:
            id: process_barcode
            ean: !lambda 'return std::string(x);'

  - platform: template
    id: last_ean
    name: "EAN"

  - platform: template
    id: last_brand
    name: "Brand"

  - platform: template
    id: last_product
    name: "Product"

# ---- I²C + Display ----
i2c:
  sda: ${display_i2c_sda}
  scl: ${display_i2c_scl}
  scan: true
  frequency: 400kHz

font:
  - file: "gfonts://Roboto"
    id: font_small
    size: 12
    glyphs: '!?"%()+*=,-_.:°/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz€@<>äöüÄÖÜß'

  - file: "gfonts://Roboto"
    id: font_large
    size: 16
    glyphs: '!?"%()+*=,-_.:°/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz€@<>äöüÄÖÜß'

display:
  - platform: ssd1306_i2c
    model: SSD1306_128X64
    address: ${ssd1306_i2c_address}
    rotation: 180
    update_interval: 200ms
    lambda: |-
      it.printf(0, 0, id(font_small), "EAN: %s", id(last_ean).state.c_str());
      it.printf(0, 20, id(font_large), "%s", id(last_brand).state.c_str());
      it.printf(0, 40, id(font_large), "%s", id(last_product).state.c_str());

# ---- Buzzer ----
switch:
  - platform: gpio
    id: beeper
    pin: ${beeper_pin}

# ---- HTTP Request ----
http_request:
  timeout: 10s
  useragent: "esphome/barcodescanner"
  verify_ssl: false

# ---- Scripts ----
script:
  - id: init_display
    mode: restart
    then:
      - lambda: |-
          id(last_ean).publish_state("Bereit...");
          id(last_brand).publish_state("Scan starten");
          id(last_product).publish_state("");

  - id: process_barcode
    parameters:
      ean: std::string
    mode: restart
    then:
      - switch.turn_on: beeper
      - delay: 100ms
      - switch.turn_off: beeper
      - lambda: |-
          id(last_ean).publish_state(ean);
          id(last_brand).publish_state("Lade...");
          id(last_product).publish_state("Lade...");
      - script.execute:
          id: fetch_openfoodfacts
          ean: !lambda 'return ean;'

  - id: fetch_openfoodfacts
    parameters:
      ean: std::string
    mode: restart
    then:
      - http_request.get:
          url: !lambda 'return "https://world.openfoodfacts.org/api/v2/product/" + ean + "?fields=brands,product_name";'
          capture_response: true
          on_response:
            then:
              - lambda: |-
                  bool ok = json::parse_json(body, [](JsonObject root)->bool {
                    if (!root["product"].is<JsonObject>()) return false;
                    JsonObject p = root["product"];
                    if (p["product_name"].is<const char*>()) {
                      id(last_product).publish_state((std::string)p["product_name"]);
                    }
                    if (p["brands"].is<const char*>()) {
                      id(last_brand).publish_state((std::string)p["brands"]);
                    }
                    return true;
                  });
                  if (!ok || id(last_product).state.empty() || id(last_product).state == "Lade...") {
                    ESP_LOGW("barcode", "OFF liefert keine Daten -> Fallback: OpenTinDB");
                    id(fetch_opentindb).execute(ean);
                  }

  - id: fetch_opentindb
    parameters:
      ean: std::string
    mode: restart
    then:
      - http_request.get:
          url: !lambda 'return "https://opengtindb.org/?ean=" + ean + "&cmd=query&queryid=${rest_opentindb_queryid}";'
          capture_response: true
          on_response:
            then:
              - lambda: |-
                  std::string b = body;
                  auto pos = b.find("NAME=");
                  if (pos != std::string::npos) {
                    auto end = b.find("\n", pos);
                    id(last_product).publish_state(b.substr(pos+5, end-pos-5));
                  } else { id(last_product).publish_state("Nicht gefunden"); }
                  pos = b.find("BRAND=");
                  if (pos != std::string::npos) {
                    auto end = b.find("\n", pos);
                    id(last_brand).publish_state(b.substr(pos+6, end-pos-6));
                  } else { id(last_brand).publish_state("Unbekannt"); }

Musst halt nur deine OTA etc. Einstellungen anpassen.

Bei Discord ist nicht viel passiert. Ich habe nur einiges geschrieben aber wirklich neues gibt es nicht. Wichtig die python datei anzupassen mit homeassistant/… und die andere sensor datei auch.

jetzt stehe ich auf dem Schlauch, muß das noch “von irgendjemandem” gemacht werden oder muß ich das bei mir machen, damit ich testen kann? Wenn ja wie?

was gleich zu Anfang auffällt: Du hast da bei ESP32 ein anderes Teil drin
so sieht das bei mir aus … später mehr, muß gleich weg.

esp32:
  board: wemos_d1_mini32
  framework:
    type: arduino
  flash_size: 4MB

Ist doch das gleiche Board. Ich habe mich an der yaml von Daniel orientiert.

Und ja du musst in beiden Fällen /config/ mit /homeassistant/ austauschen weil die Pfade angepasst wurden bei den letzt ha Updates.

mein D1_mini32 ist irgendwie abgekackt. Habe überhaupt keinen Zugriff mehr, meldet sich nicht im WLAN an und wird am USB auch nicht erkannt. Kann man den irgendwie kaputt machen, zB indem man einfach das USB-Kabel abzieht?
Ich habe aber irgendwo noch einen in Reserve, muß ich nur erst wiederfinden…

und du machst das alles mit der aktuellen ESPHome vers. 2025.11.4

hab ich immer noch nicht verstanden, bitte etwas genauer, muß die Anpassung im yaml-code passieren?
Ich dachte, Dein code oben ist bereits die aktuelle Version.