Gå til innhold
  • Bli medlem
Støtt hjemmeautomasjon.no!

The Bartender - Automatisk drikke smaker bedre


Når man har automatisert lys, varme, dørlåser, garasjeporter, sengetepper, og så videre, så er selvfølgelig spørsmålet: "Hvordan kan jeg nå gjøre livet enklere for meg selv?" Svaret er åpenbart: Den tiden det tar å helde drikke fra en beholder til et glass er jo helt bortkastet, så det må jo automatiseres!

 

Og så er det jo selvfølgelig kulere. ;) 

 

Dermed ble The Bartender™ født. En liten 5V slangepumpe styrt av en ESP8266, et par slangelengder, litt tålmodighet, og voila!

 

 

Den kan selvfølgelig gjøre mer enn det:

 

 

Deler

 

Oppkobling

Koble 3V og GND på NodeMCUen til VCC og GND på reléet. Koble D1 på NodeMCUen til Vin på reléet.

Utgangene på releet kobles i serie på strømforsyningen.

 

20201125_201543.jpg

 

 

Kode

Jeg styrer den via MQTT. Det var enkleste måten å få inn og ut data fra den uten for mye styr. Den har følgende topics.

  • /motor/get - sender status på motoren, verdi: 1 eller 0
  • /motor/set - setter motoren på eller av, verdi: 1 eller 0
  • /runtime - heltall på antall sekunder motoren skal kjøre
  • /runtimestatus - rapporterter fortløpende hvor lenge i prosent motoren har kjørt av sekunder satt med /runtime (verdi: 0-100)

 

Alt sendes til "bartender/1", det siste /1 i tilfelle jeg skulle finne på å lage noen til… ;) 

 

Du trenger Arduio Studio og ha installert PubSubClient (https://pubsubclient.knolleary.net)

 

Bartender.ino:

Spoiler


#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#define RelayPin 5    //D1
#define BUILTIN_LED 2 //D0

const char *ssid = "WIFI-SSID";
const char *password = "WIFI-PASSORD";
const char *mqtt_server = "IP_TIL_BROKER";

String clientId = "bartender1";
const char *topic = "bartender/1";
const char *motor_topic = "bartender/1/motor/set";
const char *motor_status_topic = "bartender/1/motor/get";
const char *runtime_topic = "bartender/1/runtime";
const char *runtime_status_topic = "bartender/1/runtimestatus";

unsigned long lastMotorSet;
unsigned long lastRuntimeSet;
unsigned long lastRuntimeUpdate;
float runtimeOriginal;
float runtime;
int motorStatus;
bool ignoreNextMotorStatusMessage;

WiFiClient espClient;
PubSubClient client(espClient);

void setup()
{
  //Set pins at output
  pinMode(BUILTIN_LED, OUTPUT);
  pinMode(RelayPin, OUTPUT);

  //Turn off motor
  digitalWrite(BUILTIN_LED, HIGH);
  digitalWrite(RelayPin, HIGH);

  //Connect to wifi and MQTT broker
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

void setup_wifi()
{
  delay(10);

  // Connect to wifi
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

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

  randomSeed(micros());

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

//Handle reconnect if necessary
void reconnect()
{
  // Loop until we're reconnected
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");

    if (client.connect(clientId.c_str()))
    {
      Serial.println("connected");
      client.subscribe(motor_topic);
      client.subscribe(runtime_topic);
    }
    else
    {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 2 seconds");
      // Wait 5 seconds before retrying
      delay(2000);
    }
  }
}

//Handle incomming MQTT callbacks
void callback(char *topic, byte *payload, unsigned int length)
{
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  String stringPayload = "";
  for (int i = 0; i < length; i++)
  {
    //Serial.print((char)payload[i]);
    stringPayload = stringPayload + (char)payload[i];
  }
  //Serial.println();
  Serial.println(stringPayload);

  if (strcmp(runtime_topic, topic) == 0)
  {
    Serial.println("Detected runtime_topic");
    lastRuntimeSet = millis();
    lastRuntimeUpdate = millis();
    runtime = stringPayload.toFloat() * 1000;
    runtimeOriginal = runtime;
  }

  if (strcmp(motor_topic, topic) == 0)
  {
    // if (ignoreNextMotorStatusMessage == false)
    // {
      Serial.println("Detected motor_topic");
      lastMotorSet = millis();
      if (stringPayload == "1")
        if (motorStatus == 0)
          MotorOn();
      if (stringPayload == "0")
        if (motorStatus == 1)
          MotorOff();
  }
}

unsigned long lastReadTime;
void loop()
{

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

  delay(1);

  if (runtime > 0)
  {
    runtime = runtime - (millis() - lastRuntimeUpdate);
    lastRuntimeUpdate = millis();
  }
  if (runtime < 0)
    runtime = 0;

  if (lastRuntimeSet > lastMotorSet)
  {
    if (runtime > 0)
    {
      if (motorStatus == 0)
      {
        //ignoreNextMotorStatusMessage = true;
        MotorOn();
      }
    }
    else
    {
      if (motorStatus == 1)
      {
        //ignoreNextMotorStatusMessage = true;
        MotorOff();
      }
    }
  }

  if (millis() - lastReadTime > 250)
  {
    if (motorStatus == 1 && runtime > 0)
    {
      float percent = (runtimeOriginal - runtime) / runtimeOriginal * 100;
      String percenString = String(percent, 0);
      client.publish(runtime_status_topic, percenString.c_str());
      Serial.print(percent);
      Serial.print("% -- ");
    }

    Serial.println(runtime);
    lastReadTime = millis();
  }
}

void MotorOn()
{
  motorStatus = 1;

  digitalWrite(RelayPin, LOW);
  digitalWrite(BUILTIN_LED, LOW);

  client.publish(motor_status_topic, "1");
  client.publish(runtime_status_topic, "0");
  Serial.println("Turning on...");
}

void MotorOff()
{
  motorStatus = 0;

  digitalWrite(BUILTIN_LED, HIGH);
  digitalWrite(RelayPin, HIGH);

  client.publish(motor_status_topic, "0");
  client.publish(runtime_status_topic, "100");
  Serial.println("Turning off...");
}

 

 

I HomeSeer ser det slik ut:

image.png

 

… som er satt opp i mscMQTT slik:

image.png

 

Dette kan man selvsagt enkelt legge til andre systemer, som Home Assistant, Node-Red eller Homey hvis man ønsker.  :)

 

Kalibrering

En typisk drink er visstnok 40 ml. Jeg hadde et målebeger og kjørte pumpa til det nådde opp til 0,4 dl. Det tok 19,5 sekunder som jeg runder opp til 20. Dermed får vi sammenhengen

 

Kjøretid = Drink_størrelse * (20 sek /40 ml) = ca. drinkstørrelse * 0,5.

 

Men det kan være annerledes for din pumpe og strømforsyning.

 

 

Alexa

Den øverste devicen (merket 4052) er egentlig bare på/av som er lagt inn i Alexa. Der har jeg også bare laget en rutine som skrur på device 4052 når Alexa hører "pour me a drink". Når devicen blir skrudd på har jeg et event som sender "20" til topic "/runtime", og skrur seg selv av (dvs. til "inactive" etter 20 sekunder).

 

image.png

 

 

 

Så nå står den her på kjøkkenbenken. Tror jeg må få meg et barskap den kan passe inn i...

20201125_201449.jpg 20201125_201512.jpg

 

  • Like 2
  • Haha 2

2 kommentarer


Anbefalte kommentarer

kåres

Skrevet

🙌🏼 Jeg har langt fra samme kompetanse og ser for meg at det hadde blitt et evighetsprosjekt, men så med ett for meg å sette opp denne med et knippe gode ingredienser. 
dispenser1 - vodka

dispenser2 - gin

dispenser3 - ingefærøl

dispenser4 - tonic

dispenser5 - limejucie

 

Alexa make a moscow mule

20sek dispenser1 - 5 sek dispenser5 - 80sek dispenser3

 

Alexa make a gin tonic

20sek dispenser2 - 60sek dispenser4 - 2sek dispenser5

 

Hadde vært genialt en sen lørdagskveld når man egentlig har lyst på en GT men ikke "orker" å lage 😂

 

  • Like 1
  • Haha 2
Moskus

Skrevet

16 timer siden, kåres skrev:

Hadde vært genialt en sen lørdagskveld når man egentlig har lyst på en GT men ikke "orker" å lage 😂

Må bygge den inn i et kjøleskap, men det er jo mulig! :D 

Gjest
Skriv en kommentar...

×   Du har limt inn tekst med formatering.   Lim inn uten formatering i stedet

  Du kan kun bruke opp til 75 smilefjes.

×   Lenken din har blitt bygget inn på siden automatisk.   Vis som en ordinær lenke i stedet

×   Tidligere tekst har blitt gjenopprettet.   Tøm tekstverktøy

×   Du kan ikke lime inn bilder direkte. Last opp eller legg inn bilder fra URL.

×
×
  • Opprett ny...

Viktig informasjon

Vi har plassert informasjonskapsler/cookies på din enhet for å gjøre denne siden bedre. Du kan justere dine innstillinger for informasjonskapsler, ellers vil vi anta at dette er ok for deg.