Jeff Sawyer

EARNING Trust and unlocking HUMAN potential


Author: Jeff Sawyer

  • This is Wild: I Built an Oregon Trail-Like App in 120 Seconds

    This is Wild: I Built an Oregon Trail-Like App in 120 Seconds

    You read that right. Two minutes.

    I’m still kind of blown away by this, so I had to share it.

    I had a nostalgic whim today and thought, “How hard would it be to make a super-simple, text-based game like the classic Oregon Trail?” You know—manage resources, make choices, and try not to die of dysentery.

    On impulse, I opened up Claude and typed out the basic idea. I didn’t spend ages crafting the perfect prompt. I just explained the core concept: a journey, some resources (food, water), random events, and a destination.

    I hit enter, and about two minutes later, it spat out the code.

    I copied it, ran it, and… it worked.

    Now, let’s be clear: it’s not going to win any awards. It’s simple, text-based, and probably buggy as heck. But that’s not the point.

    The point is that we’re at a place with AI where a fun, random idea can become a tangible thing in the time it takes to make a cup of coffee. The barrier from “what if” to “look at this” has basically evaporated.

    Anyway, just a fun little experiment on a Friday. What a time to be alive!

  • “They Aren’t Different From You.” The Mindset Shift That Unlocks Life-Changing Confidence.

    This past weekend, I took my kids—ages 14 and 11—to a football game at my alma mater, USC. For us, game day has a specific ritual. It starts long before kickoff. We walk through campus, stop by the bookstore, and I share stories about the legacy of the place.

    As we walk past the engineering school, I don’t just talk about the buildings; I talk about the people. I tell them about figures like Neil Armstrong and Andrew Viterbi, individuals whose work fundamentally shaped technology and exploration. Then, we walk to the Coliseum with 70,000 other fans and watch the game.

    The purpose of this ritual isn’t just nostalgia or school pride. It’s a deliberate effort to teach my children a single, critical lesson: The people we classify as “great” are fundamentally no different than they are.

    The Pedestal Problem

    Think back to when you were young. Whether it was looking up at professional athletes, brilliant scientists, or successful business leaders, we often create a narrative that “they” possess some innate, almost magical quality that separates them from “us.”

    This creates what I call the “pedestal problem.” We place successful individuals so high above us that the distance feels insurmountable. This mindset, often formed in childhood, quietly follows us into our professional lives. It manifests as imposter syndrome.

    It’s the voice that whispers:

    • “I could never start my own company; I’m not like them.”
    • “I shouldn’t apply for that promotion; I don’t have the background of the people in that room.”
    • “I can’t speak up in this meeting; my ideas aren’t as valuable as the senior executives’.”

    This fear-based perspective doesn’t just limit our ambitions; it prevents us from making the very decisions that could transform our lives. We self-select out of opportunities before we even begin.

    From Intimidation to Humanization

    The antidote to the pedestal problem is humanization.

    When I talk about Neil Armstrong with my kids, I emphasize that before he was an icon, he was an engineering student who studied, failed tests, and had to learn to manage fear under extreme pressure. When I talk about innovators like Viterbi, I frame them as people who simply pursued a question or a problem with relentless curiosity until they found an answer.

    They weren’t born legends. They were people who made a series of decisions—often difficult and frightening ones—and committed to the process.

    When we shift our mindset from viewing successful people as icons to viewing them as peers who simply navigated challenges effectively, everything changes. Intimidation gives way to curiosity. Fear gives way to possibility.

    Unlocking Your Next Decision

    This change in perspective is the foundation of genuine confidence. Confidence isn’t about believing you’ll never fail. It’s about understanding that the people you admire also faced failure and doubt, yet they proceeded anyway.

    In your career, this translates directly to action:

    1. Reframe Networking: Don’t approach industry leaders as a fan seeking an autograph. Approach them as a peer genuinely curious about the problems they solved and the decisions they made. You’ll find they are just people, too.
    2. Pursue “Stretch” Roles: Stop comparing your complete set of skills to a job description’s ideal requirements. Recognize that every person who previously held that role had to learn on the job. The “great” candidate you imagine is a myth.
    3. Embrace Bold Moves: The decision to launch a new venture, pivot industries, or take on a high-stakes project feels less like a leap into the unknown and more like a calculated next step when you realize that everyone who has done it before felt similar uncertainty.

    My hope for my children is that by walking those campus paths, they internalize that legacy isn’t something to be passively admired. It’s something to be actively joined. They don’t have to be the next Neil Armstrong; they just have to believe they possess the same human potential to solve hard problems and make their own impact.

    The same is true for all of us. The moment you stop seeing “them” as different and start seeing yourself as capable, you gain the confidence to make your next life-transforming decision.

  • An Automated Home: When Laziness Turns into Productivity

    Imagine this: You wake up not to a blaring alarm, but to your lights gradually brightening, mimicking the sunrise. The thermostat has already warmed the house to a comfortable 70°F, and the scent of freshly brewed coffee drifts from the kitchen. As you walk through the house, the lights you need turn on before you and switch off behind you. This isn’t a scene from a futuristic movie; it’s a glimpse into a life where mundane tasks are simply… handled. My goal has always been to engineer this exact reality—a living space that actively works for me. It’s a delightful paradox where the desire to avoid repetitive chores—what some might call laziness—becomes the driving force for technical creativity and ultimate productivity.

    The core philosophy is to transform my home from a collection of passive objects into a proactive, intelligent ecosystem. It should anticipate my needs, optimize for comfort, save money, and, most importantly, free up my time and mental energy for things that truly matter. It’s about offloading the small, daily cognitive load of “Did I turn off the lights? Did I close the garage? Is the temperature set correctly? Did I remember to open the windows before turning on the whole house fan?” so I can live with less frustration and more carefreely.


    The “Why”: More Than Just Convenience

    Before diving into the nuts and bolts, it’s important to understand the guiding principles behind my automations. They fall into three main categories:

    • Efficiency and Cost Savings: Every kilowatt-hour saved is a win for both my wallet and the environment. Automation isn’t about extravagance; it’s about precision. It means using energy only when and where it’s needed, whether it’s dimming lights that don’t need to be at full brightness or leveraging the cool night air instead of firing up the power-hungry air conditioner.
    • Comfort and Ambiance: A truly smart home feels right. It’s about creating the perfect environment for any activity. This means lights that transition to a warmer, dimmer setting in the evening to help wind down, or music that follows you from room to room. It’s the subtle art of making a space feel inviting and responsive.
    • Security and Peace of Mind: True security is more than an alarm. It’s the quiet confidence of knowing your home is secure. It’s getting a notification if a door is left open, being able to grant temporary access to a guest remotely, and having your home simulate occupancy when you’re thousands of miles away.

    Custom Solutions for a Bespoke Home 🧑‍💻

    While you can buy many smart devices off the shelf, the most powerful and satisfying automations come from custom-built solutions. For this, I turn to ESPHome, a transformative system for programming ESP32 microcontrollers that natively interacts with Home Assistant. It allows me to build hyper-specific, deeply integrated, and incredibly reliable devices that serve as the specialized organs of my smart home’s body. The ESPHome platform gives you the power to write low level code to an ESP32 microcontroller while handling the complex interactions needed to securely control those devices remotely.

    Here are a few of my favorite custom-built ESPHome projects:

    1. The Intelligent Garage Door Opener

    The garage door is often the largest and most-used entrance to a home, yet its standard opener is remarkably dumb. My ESPHome-based controller, built with a simple microcontroller and a reed switch sensor, elevates it to a key component of my home’s intelligence.

    • Deep State Awareness: The system doesn’t just send a command; it knows the door’s actual state. Is it open, closed, or in motion? This allows for powerful, context-aware automations. For instance, if the door is left open for more than ten minutes after sunset, I receive a critical alert on my phone.
    • Presence-Based Automation: The system is integrated with our phones’ location data. When the last person leaves the defined “home” geofence, it automatically checks the garage door’s status and closes it if it was left open. The reverse is true as well—as I approach home, the door can open automatically. No more fumbling for a remote.

    2. The Cost-Saving Whole House Fan Controller

    Here in Southern California, our climate gifts us with hot, sunny days followed by cool, breezy evenings. A whole house fan is the perfect tool to exploit this pattern, but it requires perfect timing. My custom controller removes the guesswork and turns the fan into a smart, energy-saving powerhouse.

    • Multi-Factor Decision Making: This automation is more than a simple temperature comparison. It pulls in data from multiple sources. The logic is as follows: IF the outside temperature is at least 3 degrees cooler than the inside temperature, AND Zigbee sensors confirm at least two windows are open THEN the fan will turn on. The system ensures that the HVAC system is turned off if the above conditions are met.
    • Dynamic Speed Control: It doesn’t just flip on and off. The fan speed is modulated based on the temperature differential (the “delta-T”). A large difference triggers a high-speed purge, while a smaller one will run the fan at a lower, quieter speed to maintain comfort and reduce noise. This is a level of nuance impossible with a manual switch, and it has drastically cut our A/C usage during the summer, spring and fall months.

    3. The Self-Sustaining Hydroponic Garden 🌱

    The dream of farm-to-table freshness is appealing, but the reality of daily gardening can be demanding. My automated hydroponic system, powered by another ESPHome device, handles the tedious work, ensuring my plants thrive with minimal intervention.

    • Closed-Loop Feedback System: This isn’t just a timed sprinkler. The system uses a suite of scientific sensors to constantly monitor the growing environment. A float sensor maintains the perfect water level in the reservoir. Peristaltic pumps precisely dose nutrients based on real-time readings from an Electrical Conductivity (EC) sensor, ensuring optimal plant food levels. Another sensor monitors pH, and the pumps add micro-doses of pH up/down solution to keep the water in the perfect range for nutrient absorption. A timer maintains the perfect flow of water and nutrients to the plants.
    • More Than a Gadget: This project is about sustainability. Hydroponics uses up to 90% less water than traditional soil gardening, and by growing my own greens and herbs, I reduce food miles and packaging waste. It’s a small, personal victory for a healthier lifestyle and a healthier planet.

    Tying It All Together: The Symphony of Integration

    These custom ESPHome devices are the soloists, but they play in a larger orchestra. A truly smart home relies on a seamless integration of different technologies and protocols, all managed by a central “brain”—in my case, Home Assistant. This central hub is where the magic happens, orchestrating communication between all my devices.

    • The Zigbee network acts as the home’s sensory nervous system. These low-power mesh devices are perfect for battery-operated sensors on windows, doors, and motion detectors. They provide the crucial data points—the “eyes and ears”—that trigger my automations. A Zigbee motion sensor in the hallway doesn’t just turn on the lights; it triggers a scene that turns the Z-Wave light switch on to 10% brightness after midnight for gentle navigation, but to 80% during the evening.
    • The Z-Wave and WiFI network provides the muscle. Known for its reliability and range, I use it for critical infrastructure like door locks and light switches. It’s the robust backbone that executes commands flawlessly. When my Z-Wave front door lock is unlocked with my personal code, it triggers a “Welcome Home” scene: the security system disarms, the thermostat adjusts to my preferred setting.

    The Journey Continues

    Building an automated home is not a destination; it’s an ongoing journey of refinement and creativity. Each solved inefficiency opens my eyes to a new possibility. What’s next? Perhaps automated blinds that adjust based on the sun’s position to optimize for natural light and heat gain, or a smart water-leak detection system.

    This fusion of DIY electronics with robust commercial products is where the real power lies. It’s proof that a little bit of “laziness,” when channeled through technology and a desire to improve one’s environment, can be the most productive force of all. It’s about building a home that doesn’t just shelter you but actively enriches your life.

  • The Sages Who Never Meant to Teach

    We usually look for mentors on conference stages or in the corner office. We expect wisdom to be delivered in a neat, inspiring package, perhaps with a power suit and a perfectly timed anecdote. But I’m learning that life’s most profound teachers—the real sages—often show up in the most unusual places, and they rarely come bearing gifts. In fact, sometimes they come bearing a whole lot of difficulty.

    They aren’t the wise, gentle guides we picture, offering comforting words and clear directions. Instead, their “lessons” come disguised as challenges that push every button you have, forcing you out of your comfort zone and into uncharted territory.

    For a planner like me, someone who runs on consistency, thrives on structure, and holds a firm belief in fairness, this has been… an adjustment. A massive one. My most powerful teacher lately hasn’t been a traditional mentor, but a series of events and interactions that forced me to throw the playbook out the window entirely. It’s been an unexpected masterclass in adaptability, a crash course in developing a thicker skin than I ever knew I needed.

    These unlikely sages don’t offer wisdom willingly or intentionally. Their instruction is often indirect, delivered through the very obstacles they present. By forcing us to navigate chaos and unpredictability, by challenging our core assumptions about how things “should” be, they teach us how to bend without breaking. They teach us to find our own stability and resilience when the world won’t provide it for us, or even actively tries to take it away. They show us that our capacity for strength is far greater than we imagined.

    It’s a tough curriculum, for sure. There are no easy A’s, and the homework often feels overwhelming. But the growth is undeniable. When you come out the other side, you realize you’re not just surviving; you’re thriving in a new, more robust way. You’ve learned to dance in the rain, even when it feels like a hurricane.

    Who has been an unexpected sage in your life? What difficult lesson, delivered by an unconventional teacher, ended up being exactly what you needed?

  • Bar BEE Tender: From Cocktail Napkin Idea to Smart Device

    Every great project starts with a simple idea. For me, it was about blending classic mixology with interactive technology. I wanted to create more than just a drink dispenser; I wanted to create an experience. The result was Bar BEE Tender, a smart robotic bartender that crafts the perfect Old Fashioned, but only after you prove your worth in a classic game of “Simon.”

    The concept was simple: the better you play, the more you get. As the evening progresses and more drinks are poured, the game’s memory sequence gets longer, adding a fun, challenging twist to a social gathering. It was an idea born from a desire to make technology fun, engaging, and a true centerpiece for connection.

    The Concept: A Gamified Mixology Experience

    Bar BEE Tender is an automated cocktail machine designed to pour a perfect Old Fashioned. The user interacts with a sleek touchscreen interface to start a game of “Simon.” Upon successfully completing the sequence, the machine precisely dispenses the ingredients—whiskey, bitters, and sugar—directly into your glass. With each drink poured, the challenge intensifies as the sequence length increases.

    Core Features:

    • Gamified Dispensing: A “Simon” memory game that increases in difficulty.
    • Precision Mixology: Utilizes precise pumps and measurements for a consistently perfect Old Fashioned every time.
    • Smart Connectivity: Wi-Fi enabled for IoT integration, including voice commands via Amazon Alexa.
    • Mobile Management: A companion Android app for controlling the device, tracking usage, and managing settings.

    The Technology Stack: Bringing Bar BEE Tender to Life

    This project was a deep dive into full-stack product development. I personally designed, built, and coded every component, from the physical hardware to the cloud-based services.

    Hardware: The heart of Bar BEE Tender is a custom-designed system built around a ESP32 microcontroller that controls a series of peristaltic pumps for accurate liquid dispensing. THe ESP32 was selected for the balance between cost and functions, including embedded WiFI, Bluetooth and its multithreading capabilities. The user interface is a responsive touchscreen display, all housed in a prototype chassis designed for both functionality and aesthetic appeal.

    Hardware Block Diagram of Prototype

    Firmware & Software: The firmware was written to manage the hardware operations—reading touchscreen input, running the game logic, and controlling the motors and pumps with millisecond precision. The system’s software layer, mainly in the AWS cloud included:

    • Wi-Fi Connectivity: Allowing the device to connect to a local network.
    • Amazon Alexa Integration: I developed a custom Alexa Skill enabling users to start the machine with voice commands like, “Alexa, ask Bar BEE Tender to make me a drink.”
    • Android Application: A prototype mobile app was created to remotely control the device, monitor ingredient levels, and customize drink recipes.

    Firmware: The Brains of the Operation

    The heart of the Bar BEE Tender’s intelligence lies in its firmware. Written in Arduino (C++), this code is the bridge between the physical hardware and the user experience. Running directly on the device’s microcontroller, the firmware is responsible for orchestrating every action, from the flashing lights of the “Simon” game to the precise activation of the pumps that pour the drink.

    My approach was to build a robust, state-driven program that could reliably manage the machine’s different modes: waiting for a user (Idle), running the game (Gameplay), dispensing the cocktail (Pouring), cleaning and storage (Clean), and handling any potential issues (Error). This ensures the device operates smoothly and predictably.

    Key Firmware Responsibilities:

    • Hardware Abstraction: Writing low-level drivers to control the touchscreen, addressable LEDs, audio buzzer, and the high-precision peristaltic pumps.
    • Game Logic: Implementing the core “Simon” game, including generating random sequences, capturing user input from the touchscreen, and validating the player’s memory. The difficulty (sequence length) was programmed to increase incrementally with each drink served.
    • Precision Pouring: Calibrating and controlling the pump motors with exact timing to dispense the precise volume of each ingredient—the key to a perfect Old Fashioned, every time.
    • State Management: A finite state machine (FSM) ensures the device is always in a known state, preventing conflicts like trying to pour a drink while a game is in progress.
    • Communication with AWS IOT: Syncing of local state and remote state using the AWS IOT framework.

    Below is the full firmware.

    /*
    Copyright (C) 2023 Jeffrey Sawyer - All Rights Reserved
    Project:      Bar BEE Tender Firmware
    Created by:   Jeff Sawyer on 6/30/23
    */
    #include "secrets.h"
    #include <WiFiClientSecure.h>
    #include <PubSubClient.h>
    #include <ArduinoJson.h>
    #include "WiFi.h"
    const byte dwinrxPin = 16;  //rx2
    const byte dwintxPin = 17;  //tx2
    HardwareSerial dwin(1);
    #include <Arduino.h>
    #include <Wire.h>
    #include <PCF8575.h>  //https://github.com/xreef/PCF8575_library
    #include <EEPROM.h>
    #define EEPROM_SIZE 1028
    #define GPIO1_Addr 0x20
    PCF8575 pcf8575_1(GPIO1_Addr);
    #define STATE_INIT 0
    #define STATE_OLDFASHIONED 1
    #define STATE_BOURBONSHOT 2
    #define STATE_VODKASHOT 3
    #define STATE_SETUP 4
    #define STATE_MAX 4
    // the main switch
    #define rtsw 5
    // define the pins that will be used for the pumps
    #define pump1_p P0
    #define pump1_n P1
    #define pump2_p P2
    #define pump2_n P3
    #define pump3_p P4
    #define pump3_n P5
    #define pump4_p P6
    #define pump4_n P7
    #define debug_pin 16
    #define DRINKS_COUNTER_ADDRESS 0
    TaskHandle_t Task1;
    boolean TurnDetected;
    boolean up;
    boolean insleep = 0;
    boolean triggersleep = 0;
    boolean entersleep = 0;
    boolean exitsleep = 0;
    boolean aborttask = 0;
    bool use_lcd = 0;
    bool SS_enabled = 1;
    // Assign pins for buttons, leds and buzzer for simon
    const int buttonPins[] = { P9, P11, P13, P15 };
    const int ledPins[] = { P8, P10, P12, P14 };
    const int buzzer = 26;  // TODO this needs to be assigned to the correct pin
    // These are the tones used for the buzzer using Hertz (Hz).
    const int tones[] = { 1900, 1600, 1300, 1000, 3200 };
    const int clean_steps = 5;
    const int clean_time = 10;
    const int soak_time = 50;
    const int purge_time = 10;
    const int prime_time = 1;
    int wifi_timeout = 10;
    boolean wifi_found = 0;
    int wifi_networkid = 1;
    char* wifi_hostname = "BarBeeTender";
    char* wifi_ssid0 = "cackandballs";
    char* wifi_password0 = "*********";
    char* wifi_ssid1 = "Anteater";
    char* wifi_password1 = "*********";
    char* wifi_ssid2 = "pabsthouse";
    char* wifi_password2 = ""*********";
    char* wifi_ssid = wifi_ssid0;
    char* wifi_password = wifi_password0;
    // SS veriables
    int buttonState[] = { 0, 0, 0, 0 };      //  Current state of button.
    int lastButtonState[] = { 0, 0, 0, 0 };  // Previous state of button.
    int buttonCounter[] = { 0, 0, 0, 0 };    // This array holds 4 values - 1 (pressed) / 0 (not pressed).
    int gameOn = 0;                          // A new game or level starts when gameOn is 0.
    int wait = 0;                            // This is used to tell the game to wait until the player inputs a pattern.
    const int n_levels = 100;                // Length of series per level and number of levels until game is won.
    int currentLevel = 1;                    // Current game level and length of sequence to make it to the next level.
    int dlay = 500;                          // This is the amount of time to wait for the next button press (0.5 seconds).
    int ledTime = 500;                       // Delay time of each LED flash when the correct button is pressed (0.5s).
    int pinAndTone = 0;                      // Variable used to determine which LED to turn on and its buzzer tone.
    int correct = 0;                         // This value must become 1 to go to the next level.
    int speedFactor = 5;                     // This is the speed of the game. It increases every time a level is beaten.
    int ledDelay = 200;                      // Delay before next LED lights up (0.2s). Decreases when level is completed.
    int SS_level = 0;
    int SS_unlocked = 0;
    char temp_status_message[50];
    int n_array[n_levels];  // n_array will store the randomized game pattern.
    int u_array[n_levels];  // u_array will store the pattern input by the player.
    int connectedfl = 0;
    int trigger_pour = 0;
    int trigger_pour_source = 0;
    String drinktype = "";
    int pouring = 0;
    int cleaning = 0;
    int purging = 0;
    int priming = 0;
    char AWS_PUBLISH_TOPIC[] = "$aws/things/" THINGNAME "/shadow/update";
    char AWS_GET_TOPIC[] = "$aws/things/" THINGNAME "/shadow/get";
    char* AWS_SUBSCRIBE_TOPIC[5] = {
    "$aws/things/" THINGNAME "/shadow/get/accepted",
    "$aws/things/" THINGNAME "/shadow/get/rejected",
    "$aws/things/" THINGNAME "/shadow/update/accepted",
    "$aws/things/" THINGNAME "/shadow/update/rejected",
    "$aws/things/" THINGNAME "/shadow/update/delta"
    };
    char publishPayload[MQTT_MAX_PACKET_SIZE];
    // interrupt handler for the turn detection of the rotary input device
    void isr1() {
    if (pouring || cleaning || purging || priming) {  // if (pouring || cleaning) {
    aborttask = 1;
    } else {
    //log_d("button pressed STATE_INIT insleep=%d, entersleep=%d, exitsleep=%d", insleep, entersleep, exitsleep);
    if (insleep == 0) {
    //log_d("Enter sleep");
    triggersleep = 1;
    entersleep = 1;
    } else {
    //log_d("Exit sleep");
    triggersleep = 0;
    exitsleep = 1;
    }
    }
    }
    // return the number of drinks that have been made which is stored in the eeprom
    byte get_lifetime_drinks() {
    byte lifetime_drinks;
    EEPROM.get(DRINKS_COUNTER_ADDRESS, lifetime_drinks);
    set_touch_numdrinks(lifetime_drinks);
    return lifetime_drinks;
    }
    // reset the number of drinks eeprom value
    void reset_lifetime_drinks() {
    EEPROM.write(DRINKS_COUNTER_ADDRESS, 0);
    EEPROM.commit();
    set_touch_numdrinks(0);
    }
    // increment the number ofr drinks counter and update the eeprom
    void increment_drinks() {
    byte lifetime_drinks;
    EEPROM.get(DRINKS_COUNTER_ADDRESS, lifetime_drinks);
    lifetime_drinks = lifetime_drinks + 1;
    EEPROM.write(DRINKS_COUNTER_ADDRESS, lifetime_drinks);
    EEPROM.commit();
    set_touch_numdrinks(lifetime_drinks);
    }
    WiFiClientSecure net = WiFiClientSecure();
    PubSubClient PSclient(net);
    void getState() {
    if (PSclient.publish(AWS_GET_TOPIC, "{}")) {
    log_d("Getting Something from AWS_GET_TOPIC");
    PSclient.loop();
    } else {
    log_d("Not Getting Something from AWS_GET_TOPIC");
    };
    }
    void connectAWS() {
    int wifi_trycounter = 0;
    WiFi.mode(WIFI_STA);
    WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE, INADDR_NONE);
    WiFi.setHostname(wifi_hostname);  //define hostname
    wifi_found = (WiFi.status() == WL_CONNECTED);
    while (!wifi_found) {
    wifi_trycounter = 0;
    connectedfl = 0;
    WiFi.begin(wifi_ssid, wifi_password);
    log_d("Connecting to Wi-Fi %s %s ", wifi_ssid, wifi_password);
    while (WiFi.status() != WL_CONNECTED && wifi_trycounter < wifi_timeout) {
    delay(500);
    log_d(".");
    wifi_trycounter++;
    }
    if (WiFi.status() == WL_CONNECTED) {
    wifi_found = 1;
    log_d("Connected to Wi-Fi %s %s ", wifi_ssid, wifi_password);
    set_top_icon(0, 1);
    } else {
    wifi_found = 0;
    set_top_icon(0, 0);
    wifi_networkid++;
    if (wifi_networkid > 2) {
    wifi_networkid = 0;
    }
    if (wifi_networkid == 0) {
    wifi_ssid = wifi_ssid0;
    wifi_password = wifi_password0;
    } else if (wifi_networkid == 1) {
    wifi_ssid = wifi_ssid1;
    wifi_password = wifi_password1;
    } else {
    wifi_ssid = wifi_ssid2;
    wifi_password = wifi_password2;
    }
    log_d("Failed t find Wi-Fi, switching to %s %s wifi_networkid=%d", wifi_ssid, wifi_password, wifi_networkid);
    }
    }
    // Configure WiFiClientSecure to use the AWS IoT device credentials
    net.setCACert(AWS_CERT_CA);
    net.setCertificate(AWS_CERT_CRT);
    net.setPrivateKey(AWS_CERT_PRIVATE);
    // Connect to the MQTT broker on the AWS endpoint we defined earlier
    PSclient.setBufferSize(1024);
    PSclient.setServer(AWS_IOT_ENDPOINT, 8883);
    // Create a message handler
    PSclient.setCallback(callback);
    log_d("Connecting to AWS IOT");
    while (!PSclient.connect(THINGNAME)) {
    log_d(".");
    delay(100);
    }
    if (!PSclient.connected()) {
    log_d("AWS IoT Timeout!");
    return;
    }
    // Subscribe to a topic
    for (int i = 0; i < 5; i++) {
    if (PSclient.subscribe(AWS_SUBSCRIBE_TOPIC[i])) {
    log_d("Connected to %s\n", AWS_SUBSCRIBE_TOPIC[i]);
    } else {
    log_d("Not connected to %s\n", AWS_SUBSCRIBE_TOPIC[i]);
    }
    }
    log_d("AWS IoT Connected!");
    }
    void updateIOTState(String istate_type, int itrigger_pour) {
    const char* temp_drinktype = drinktype.c_str();
    sprintf(publishPayload, "{\"state\":{\"%s\":{\"connectedfl\":%d,\"trigger_pour\":%d,\"drinktype\":\"%s\",\"pouring\":%d,\"cleaning\":%d,\"purging\":%d,\"priming\":%d,\"num_drinks\":%d,\"localip\":\"%s\",\"subnetmask\":\"%s\",\"wifi\":\"%s\"}}}",
    istate_type, connectedfl, itrigger_pour, temp_drinktype, pouring, cleaning, purging, priming, get_lifetime_drinks(), String(WiFi.localIP()), WiFi.subnetMask().toString(), wifi_ssid);
    PSclient.publish(AWS_PUBLISH_TOPIC, publishPayload);
    log_d("Publish [%s] %s  \ndrinktype:%s\n", AWS_PUBLISH_TOPIC, publishPayload, temp_drinktype);
    }
    void callback(char* topic, byte* payload, unsigned int length) {
    //char buf[MQTT_MAX_PACKET_SIZE];
    // Create a buffer for the incoming payload
    char message[length + 1];
    strncpy(message, (char*)payload, length);
    message[length] = '\0';
    printf("Message arrived [%s] %s\r\n", topic, message);
    if ((strstr(topic, "/shadow/get/accepted") != NULL) || (strstr(topic, "/shadow/update/accepted") != NULL)) {
    // Parse JSON
    DynamicJsonDocument doc(1024);
    DeserializationError error = deserializeJson(doc, message);
    if (error) {
    Serial.print("deserializeJson() failed: ");
    Serial.println(error.f_str());
    return;
    }
    // Extract values (modify according to your JSON structure)
    //const char* state = doc["state"]["desired"]["yourPropertyName"];
    //Serial.println(state);
    JsonVariant exists_n = doc["state"]["desired"];
    if (!exists_n.isNull()) {
    // connectedfl = doc["state"]["desired"]["connectedfl"];
    trigger_pour = doc["state"]["desired"]["trigger_pour"];
    trigger_pour_source = 1;
    const char* temp_drinktype = doc["state"]["desired"]["drinktype"];
    //String temp_drinktype = sprintf("%s", obj["state"]["desired"]["drinktype"]);
    // pouring = doc["state"]["desired"]["pouring"];
    drinktype = String(temp_drinktype);
    log_d("callback connectedfl=%d trigger_pour=%d drinktype=%s pouring=%d", connectedfl, trigger_pour, drinktype, pouring);
    }
    }
    }
    // this is the Simmon Says test routine, called when the user wants to make a drink and SS is enabled
    void SS_test() {
    // wait for unlock
    int SS_unlocked = 0;
    int i;
    int fail_count = 0;
    String locked_str = "";
    if (SS_enabled && !trigger_pour_source) {
    currentLevel = get_lifetime_drinks() + 1;
    set_touch_page(52);
    sprintf(temp_status_message, "Game Level: %d:  Good Luck!.", currentLevel);
    set_status_text(temp_status_message);
    // play the game
    while (SS_unlocked == 0) {
    if (wait == 0) {  // Triggers if no action is required from the player.
    i = 0;
    for (i = 0; i < currentLevel; i = i + 1) {  // This ‘for’ loop cycles the current game pattern.
    ledDelay = ledTime / (1 + (speedFactor / n_levels) * (currentLevel - 1));
    pinAndTone = n_array[i];
    //pcf8575_1.digitalWrite(ledPins[pinAndTone], HIGH);
    set_game_light(pinAndTone, 1);
    playTone(tones[pinAndTone], ledDelay);
    //pcf8575_1.digitalWrite(ledPins[pinAndTone], LOW);
    set_game_light(pinAndTone, 0);
    delay(100);
    log_d("Show user: %i : %i", i, pinAndTone);
    }
    wait = 1;  // This puts the game on hold until the player enters a pattern.
    }
    set_touch_page(2);
    i = 0;
    int buttonChange = 0;
    // buttonChange will be used to detect when a button is pressed.
    int j = 0;  // ‘j’ is the current position in the pattern.
    while (j < currentLevel) {
    while (buttonChange == 0) {
    unsigned char button_value = get_button_press();
    for (i = 0; i < 4; i = i + 1) {  // This loop determines which button is pressed by the player.
    // pcf8575_1.digitalWrite(buttonPins[i], HIGH);
    buttonState[i] = bitRead(button_value, i);
    buttonChange += buttonState[i];
    if (buttonChange > 0) {
    log_d("Buttons: buttonState[%i]=%i buttonChange=%i", i, buttonState[i], buttonChange);
    }
    }
    delay(10);  // this delay has to be here to allow for the read,   should try and do the read in a single call
    }
    // This turns on the corresponding LED to the button pressed, and stores it in the array.
    for (i = 0; i < 4; i = i + 1) {
    if (buttonState[i] == 1) {
    set_game_light(i, 1);
    playTone(tones[i], ledTime);  // Calls function playTone, plays corresponding tone on the buzzer.
    set_game_light(i, 0);
    wait = 0;
    u_array[j] = i;  // This stores the player’s input to be matched against the game pattern.
    buttonState[i] = LOW;
    buttonChange = 0;  // This resets the button.
    }
    }
    if (u_array[j] == n_array[j]) {
    correct = 1;
    log_d("Correct: %i", n_array[j]);
    j++;
    }
    // This section checks if the button pressed by the player matches the game pattern.
    else {
    correct = 0;
    i = 4;
    j = currentLevel;
    wait = 0;
    log_d("Incorrect: expected: %i received %i", n_array[j], u_array[j]);
    }
    }
    // If the player makes a mistake, these variables will be reset so that the game starts over.
    if (correct == 0) {
    set_touch_page(52);
    fail_count = fail_count + 1;
    if (fail_count > 1) {
    int randomNumber = random(4);
    switch (randomNumber) {
    case 0:
    sprintf(temp_status_message, "Game Level: %d:  Loser you failed again.", currentLevel);
    break;
    case 1:
    sprintf(temp_status_message, "Game Level: %d:  Are you kidding me?", currentLevel);
    break;
    case 2:
    sprintf(temp_status_message, "Game Level: %d:  What a shit play", currentLevel);
    break;
    case 3:
    sprintf(temp_status_message, "Game Level: %d:  Did your mother drop you?", currentLevel);
    break;
    }
    } else {
    sprintf(temp_status_message, "Game Level: %d:  You are a failure!", currentLevel);
    }
    set_status_text(temp_status_message);
    delay(300);
    i = 0;
    gameOn = 0;
    // this needs to be rewritten to write all the bits at the same time.
    for (i = 0; i < 4; i = i + 1) {
    set_game_light(i, 1);
    }
    playTone(tones[4], ledTime);
    for (i = 0; i < 4; i = i + 1) {
    set_game_light(i, 0);
    }
    delay(200);
    for (i = 0; i < 4; i = i + 1) {
    set_game_light(i, 1);
    }
    playTone(tones[4], ledTime);
    // This "for loop" makes all of the LEDs blink twice and the buzzer beep twice when the player makes a mistake and loses the game.
    for (i = 0; i < 4; i = i + 1) {
    set_game_light(i, 0);
    }
    delay(500);
    gameOn = 1;
    SS_unlocked = 0;
    log_d("failed, still locked");
    for (i = 0; i < n_levels; i = i + 1) {
    u_array[i] = 0;
    }
    }
    if (correct == 1) {  // If the player gets the sequence right, the game goes up one level.
    wait = 0;
    set_touch_page(52);
    SS_unlocked = 1;
    Serial.println("unlocked");
    }
    }
    }
    sprintf(temp_status_message, "");
    set_status_text(temp_status_message);
    }
    // control the motors, either forward or reverse
    void control_motor(int motor_num, int motor_direction) {
    if (motor_direction == 1) {  // forward
    if (motor_num == 1) {
    log_d("Motor 1 ON FORWARD");
    pcf8575_1.digitalWrite(pump1_p, LOW);
    pcf8575_1.digitalWrite(pump1_n, HIGH);
    }
    if (motor_num == 2) {
    log_d("Motor 2 ON FORWARD");
    pcf8575_1.digitalWrite(pump2_p, LOW);
    pcf8575_1.digitalWrite(pump2_n, HIGH);
    }
    if (motor_num == 3) {
    log_d("Motor 3 ON FORWARD");
    pcf8575_1.digitalWrite(pump3_p, LOW);
    pcf8575_1.digitalWrite(pump3_n, HIGH);
    }
    if (motor_num == 4) {
    log_d("Motor 4 ON FORWARD");
    pcf8575_1.digitalWrite(pump4_p, LOW);
    pcf8575_1.digitalWrite(pump4_n, HIGH);
    }
    } else if (motor_direction == -1) {
    if (motor_num == 1) {
    log_d("Motor 1 ON REVERSE");
    pcf8575_1.digitalWrite(pump1_p, HIGH);
    pcf8575_1.digitalWrite(pump1_n, LOW);
    }
    if (motor_num == 2) {
    log_d("Motor 2 ON REVERSE");
    pcf8575_1.digitalWrite(pump2_p, HIGH);
    pcf8575_1.digitalWrite(pump2_n, LOW);
    }
    if (motor_num == 3) {
    log_d("Motor 3 ON REVERSE");
    pcf8575_1.digitalWrite(pump3_p, HIGH);
    pcf8575_1.digitalWrite(pump3_n, LOW);
    }
    if (motor_num == 4) {
    log_d("Motor 4 ON REVERSE");
    pcf8575_1.digitalWrite(pump4_p, HIGH);
    pcf8575_1.digitalWrite(pump4_n, LOW);
    }
    } else {
    if (motor_num == 1) {
    log_d("Motor 1 OFF");
    pcf8575_1.digitalWrite(pump1_p, LOW);
    pcf8575_1.digitalWrite(pump1_n, LOW);
    }
    if (motor_num == 2) {
    log_d("Motor 2 OFF");
    pcf8575_1.digitalWrite(pump2_p, LOW);
    pcf8575_1.digitalWrite(pump2_n, LOW);
    }
    if (motor_num == 3) {
    log_d("Motor 3 OFF");
    pcf8575_1.digitalWrite(pump3_p, LOW);
    pcf8575_1.digitalWrite(pump3_n, LOW);
    }
    if (motor_num == 4) {
    log_d("Motor 4 OFF");
    pcf8575_1.digitalWrite(pump4_p, LOW);
    pcf8575_1.digitalWrite(pump4_n, LOW);
    }
    }
    }
    void prime() {
    log_i("Priming");
    priming = 1;
    set_touch_page(51);
    updateIOTState("reported", 0);
    sprintf(temp_status_message, "Prime");
    set_status_text(temp_status_message);
    control_motor(1, 1);
    control_motor(2, 1);
    control_motor(3, 1);
    control_motor(4, 1);
    for (int i = 0; i <= (prime_time * 10); i++) {
    delay(100);
    int percent_complete = int((float(i) / (prime_time * 10)) * 100);
    set_touch_progress(percent_complete);
    }
    control_motor(1, 0);
    control_motor(2, 0);
    control_motor(3, 0);
    control_motor(4, 0);
    delay(100);
    set_touch_progress(0);
    priming = 0;
    updateIOTState("reported", 0);
    sprintf(temp_status_message, "");
    set_status_text(temp_status_message);
    set_touch_page(1);
    }
    void purge() {
    log_i("Purging");
    purging = 1;
    set_touch_page(51);
    updateIOTState("reported", 0);
    sprintf(temp_status_message, "Purging");
    set_status_text(temp_status_message);
    control_motor(1, -1);
    control_motor(2, -1);
    control_motor(3, -1);
    control_motor(4, -1);
    for (int i = 0; i <= (purge_time * 10); i++) {
    delay(100);
    int percent_complete = int((float(i) / (purge_time * 10)) * 100);
    set_touch_progress(percent_complete);
    }
    control_motor(1, 0);
    control_motor(2, 0);
    control_motor(3, 0);
    control_motor(4, 0);
    delay(100);
    set_touch_progress(0);
    purging = 0;
    updateIOTState("reported", 0);
    sprintf(temp_status_message, "");
    set_status_text(temp_status_message);
    set_touch_page(1);
    }
    void reset_counters() {
    log_i("Resetting counters");
    set_touch_page(51);
    reset_lifetime_drinks();
    delay(100);
    set_touch_progress(0);
    set_touch_page(1);
    }
    void clean() {
    log_i("Cleaning");
    delay(10);
    cleaning = 1;
    aborttask = 0;
    updateIOTState("reported", 0);
    int total_time = ((clean_time + soak_time) * clean_steps) + purge_time;
    int completed_time = 0;
    set_touch_page(51);
    for (int s = 1; s <= clean_steps; s++) {
    control_motor(1, 1);
    control_motor(2, 1);
    control_motor(3, 1);
    control_motor(4, 1);
    sprintf(temp_status_message, "Cleaning: Phase %d of %d Pump", s, clean_steps);
    set_status_text(temp_status_message);
    for (int i = 0; i <= clean_time; i++) {
    int percent_complete = int((float(i + completed_time) / total_time) * 100);
    set_touch_progress(percent_complete);
    delay(1000);
    if (aborttask) {
    delay(500);
    if (digitalRead(rtsw) == LOW) {
    control_motor(1, 0);
    control_motor(2, 0);
    control_motor(3, 0);
    control_motor(4, 0);
    log_d("Abort Cleaning Pump");
    set_touch_page(1);
    delay(1000);
    set_touch_progress(0);
    cleaning = 0;
    aborttask = 0;
    updateIOTState("reported", 0);
    return;
    }
    aborttask = 0;
    }
    }
    control_motor(1, 0);
    control_motor(2, 0);
    control_motor(3, 0);
    control_motor(4, 0);
    sprintf(temp_status_message, "Cleaning: Phase %d of %d Soak", s, clean_steps);
    set_status_text(temp_status_message);
    for (int i = 0; i <= soak_time; i++) {
    int percent_complete = int((float((i + clean_time) + completed_time) / total_time) * 100);
    set_touch_progress(percent_complete);
    delay(1000);
    if (aborttask) {
    delay(500);
    if (digitalRead(rtsw) == LOW) {
    control_motor(1, 0);
    control_motor(2, 0);
    control_motor(3, 0);
    control_motor(4, 0);
    log_d("Abort Cleaning Soak");
    set_touch_page(1);
    delay(1000);
    set_touch_progress(0);
    cleaning = 0;
    aborttask = 0;
    updateIOTState("reported", 0);
    return;
    }
    aborttask = 0;
    }
    }
    completed_time = completed_time + clean_time + soak_time;
    }
    control_motor(1, -1);
    control_motor(2, -1);
    control_motor(3, -1);
    control_motor(4, -1);
    sprintf(temp_status_message, "Cleaning: Purge");
    set_status_text(temp_status_message);
    for (int i = 0; i <= (purge_time); i++) {
    delay(1000);
    int percent_complete = int((float((i + purge_time) + completed_time) / total_time) * 100);
    set_touch_progress(percent_complete);
    }
    control_motor(1, 0);
    control_motor(2, 0);
    control_motor(3, 0);
    control_motor(4, 0);
    delay(1000);
    set_touch_progress(0);
    set_touch_page(1);
    cleaning = 0;
    updateIOTState("reported", 0);
    sprintf(temp_status_message, "");
    set_status_text(temp_status_message);
    }
    // pour a drink
    void pour(int m1_time, int m2_time, int m3_time, int m4_time) {
    delay(10);
    pouring = 1;
    updateIOTState("reported", trigger_pour);
    aborttask = 0;
    if (m1_time > 0) {
    control_motor(1, 1);
    }
    if (m2_time > 0) {
    control_motor(2, 1);
    }
    if (m3_time > 0) {
    control_motor(3, 1);
    }
    if (m4_time > 0) {
    control_motor(4, 1);
    }
    int max_time = m1_time;
    if (m2_time > max_time) {
    max_time = m2_time;
    }
    if (m3_time > max_time) {
    max_time = m3_time;
    }
    if (m4_time > max_time) {
    max_time = m4_time;
    }
    increment_drinks();
    log_d("max_time %i", max_time);
    for (int i = 0; i <= max_time; i++) {
    int percent_complete = int((float(i) / max_time) * 100);
    int percent_complete_bar = int((float(i) / max_time) * 18);
    String percent_complete_time_str = "";
    percent_complete_time_str += String(i);
    percent_complete_time_str += " of ";
    percent_complete_time_str += String(max_time);
    percent_complete_time_str += " seconds  ";
    String percent_complete_str = "";
    percent_complete_str += String(percent_complete);
    percent_complete_str += "% complete";
    String percent_complete_bar_str = "8";
    // percent_complete_str += String(percent_complete);
    // percent_complete_str += "% complete     ";
    for (int i = 0; i < 17; i = i + 1) {
    if (i < percent_complete_bar) {
    percent_complete_bar_str += "=";
    } else if (i == percent_complete_bar) {
    percent_complete_bar_str += "D";
    } else {
    percent_complete_bar_str += " ";
    }
    }
    percent_complete_bar_str += "O:";
    log_d("Percent complete: %i", percent_complete);
    set_touch_progress(percent_complete);
    if (i == m1_time) {
    control_motor(1, 0);
    }
    if (i == m2_time) {
    control_motor(2, 0);
    }
    if (i == m3_time) {
    control_motor(3, 0);
    }
    if (i == m4_time) {
    control_motor(4, 0);
    }
    delay(1000);
    if (aborttask) {
    delay(500);
    if (digitalRead(rtsw) == LOW) {
    control_motor(1, 0);
    control_motor(2, 0);
    control_motor(3, 0);
    control_motor(4, 0);
    set_touch_page(10);
    log_d("Abort Pouring");
    delay(1000);
    set_touch_progress(0);
    pouring = 0;
    aborttask = 0;
    updateIOTState("reported", 0);
    return;
    }
    aborttask = 0;
    }
    }
    pouring = 0;
    updateIOTState("reported", trigger_pour);
    }
    // play tones on the buzzer
    void playTone(int tone, int duration) {
    for (long i = 0; i < duration * 1000L; i += tone * 2) {
    digitalWrite(buzzer, HIGH);  // Turns the buzzer on.
    delayMicroseconds(tone);     // Creates the tone of the buzzer.
    digitalWrite(buzzer, LOW);   // Turns the buzzer off.
    delayMicroseconds(tone);
    }
    }
    void SS_init_game_pattern() {
    int i;
    for (i = 0; i < n_levels; i = i + 1) {
    // Saves the number in n_array to generate a random pattern.
    n_array[i] = 0;
    u_array[i] = 0;
    n_array[i] = random(0, 4);
    log_d("n_arry[%i]=%i", i, n_array[i]);
    }
    }
    // setup
    void setup() {
    // set the debug serial port baud rate
    Serial.begin(115200);
    dwin.begin(115200, SERIAL_8N1, dwinrxPin, dwintxPin);
    // display debug information to the debug serial port
    log_d("Total heap: %d", ESP.getHeapSize());
    log_d("Free heap: %d", ESP.getFreeHeap());
    log_d("Total PSRAM: %d", ESP.getPsramSize());
    log_d("Free PSRAM: %d", ESP.getFreePsram());
    log_d("Bar-BEE setup started");
    // make sure the eeprom is working
    if (!EEPROM.begin(EEPROM_SIZE)) {
    log_d("EEPROM failed to initialize");
    while (true)
    ;
    } else {
    log_d("EEPROM initialized");
    }
    // setup the rotary input interface
    pinMode(rtsw, INPUT_PULLUP);
    // set the the motor pins
    pcf8575_1.pinMode(pump1_p, OUTPUT);
    pcf8575_1.pinMode(pump1_n, OUTPUT);
    pcf8575_1.pinMode(pump2_p, OUTPUT);
    pcf8575_1.pinMode(pump2_n, OUTPUT);
    pcf8575_1.pinMode(pump3_p, OUTPUT);
    pcf8575_1.pinMode(pump3_n, OUTPUT);
    pcf8575_1.pinMode(pump4_p, OUTPUT);
    pcf8575_1.pinMode(pump4_n, OUTPUT);
    // this is to set the random see for the SS game
    randomSeed(analogRead(0));  // Used to generate random numbers.
    // Initialize inputs.
    reset_touch_screen();
    for (int i = 0; i < 4; i = i + 1) {
    pcf8575_1.pinMode(ledPins[i], OUTPUT);
    pcf8575_1.pinMode(buttonPins[i], INPUT);
    }
    //  connect to the external GPIO chip(s)
    pcf8575_1.begin();
    pinMode(buzzer, OUTPUT);
    SS_init_game_pattern();
    // go into a debug mode where the LCD screen is not working
    // by holding the rotary inout switch down when the unit boots the
    // lcd screen will be disabled and the led attached to the
    // debug pin will be flashed
    // wait for the wsitch to be relased before proceeding
    if (digitalRead(rtsw) == LOW) {
    use_lcd = 0;
    log_d("Debug mode, turn off LCD");
    digitalWrite(debug_pin, HIGH);
    delay(500);
    digitalWrite(debug_pin, LOW);
    delay(500);
    digitalWrite(debug_pin, HIGH);
    delay(500);
    digitalWrite(debug_pin, LOW);
    delay(500);
    while (digitalRead(rtsw) == LOW) {
    delay(100);
    }
    }
    // test is the external GPIO deviceis availible
    // if not flash the debug pin and stall the
    // program
    int GPIO_found = 0;
    while (!GPIO_found) {
    Wire.beginTransmission(GPIO1_Addr);
    log_d("Testing address for GPIO I2C chip");
    int error = Wire.endTransmission();
    if (error == 0) {
    log_d("GPIO Found");
    GPIO_found = 1;
    } else {
    log_d("GPIO Not found, retry");
    GPIO_found = 0;
    delay(1000);
    }
    }
    // turn all the motors off
    control_motor(1, 0);
    control_motor(2, 0);
    control_motor(3, 0);
    control_motor(4, 0);
    attachInterrupt(digitalPinToInterrupt(rtsw), isr1, FALLING);
    TurnDetected = false;
    // create a task that will be executed in the Task1code() function, with priority 1 and executed on core 0
    xTaskCreatePinnedToCore(
    Task1code, /* Task function. */
    "Task1",   /* name of task. */
    10000,     /* Stack size of task */
    NULL,      /* parameter of the task */
    1,         /* priority of the task */
    &Task1,    /* Task handle to keep track of created task */
    0);        /* pin task to core 0 */
    delay(500);
    log_d("Bar-BEE setup completed");
    log_d("Night drinks made:  %i", get_lifetime_drinks());
    SS_enabled = 1;
    if (SS_enabled) {
    set_top_icon(1, 2);
    } else {
    set_top_icon(1, 3);
    }
    delay(1000);
    set_touch_page(10);
    }
    // Task1code: Stay connected to AWS
    void Task1code(void* pvParameters) {
    Serial.print("Network running on core ");
    Serial.println(xPortGetCoreID());
    for (;;) {
    if (!PSclient.connected()) {
    connectAWS();
    // getState();
    }
    PSclient.loop();
    if (connectedfl == 0) {
    connectedfl = 1;
    //TODO this should not be hard coded,  it should grab from the current vars,   this could crash the running drink like this
    updateIOTState("reported", 0);
    }
    delay(100);
    }
    }
    // the main loop of the program
    void loop() {
    // always clear this flag
    aborttask = 0;
    // if the isr triggered sleep by the user pressing a button or we are in sleep
    if (triggersleep || insleep) {
    if (entersleep) {
    // do stuff to enter sleep
    log_d("Entering Sleep");
    set_touch_page(00);
    delay(1000);
    entersleep = 0;
    set_touch_page(99);
    insleep = 1;
    } else if (exitsleep) {
    // do stuff on exit sleep
    log_d("Exiting Sleep");
    set_touch_page(00);
    delay(1000);
    set_touch_page(10);
    exitsleep = 0;
    insleep = 0;
    } else {
    // do nothing
    }
    } else {
    // if not entering of exiting of in sleep then check if we need to pour a drink
    // check if we have anything to do from the screen
    // make sure that we did not get a triffer from aws first
    if (!trigger_pour) {
    trigger_pour = check_touch_screen();
    trigger_pour_source = 0;
    }
    if (trigger_pour) {
    // we can get here from the screen trggering this of AWS IOT
    trigger_pour = 0;
    //drinktype.trim();
    log_d("Pouring - triggered by remote ** %s ** ", drinktype);
    String drinktype_display = "";
    if (drinktype.equals("oldfashioned")) {
    // old fashioned
    drinktype_display = "Old Fashioned";
    } else if (drinktype.equals("bourbonshot") || drinktype.equals("bourbon")) {
    // bourbon shot
    drinktype_display = "Bourbon Shot";
    } else if (drinktype.equals("vodkashot") || drinktype.equals("vodka")) {
    // vodka shot
    drinktype_display = "Vodka Shot";
    } else {
    drinktype_display = "unknown drink";
    }
    if (drinktype.equals("oldfashioned")) {
    // old fashioned
    SS_test();
    set_touch_page(200);
    pour(16, 60, 0, 2);
    } else if (drinktype.equals("bourbonshot") || drinktype.equals("bourbon")) {
    // bourbon shot
    SS_test();
    set_touch_page(201);
    pour(0, 60, 0, 0);
    } else if (drinktype.equals("vodkashot") || drinktype.equals("vodka")) {
    // vodka shot
    SS_test();
    set_touch_page(202);
    pour(0, 0, 60, 0);
    } else {
    drinktype = "error";
    delay(3000);
    }
    drinktype = "";
    updateIOTState("reported", trigger_pour);
    clear_touch_serial_buffer();
    set_touch_page(10);
    set_touch_progress(0);
    }
    }
    }
    int check_touch_screen() {
    int return_code = 0;
    unsigned char Buffer[9];
    if (dwin.available()) {
    for (int i = 0; i <= 8; i++)  //this loop will store whole frame in buffer array.
    {
    Buffer[i] = dwin.read();
    }
    if (Buffer[0] == 0X5A && Buffer[1] == 0XA5 && Buffer[3] == 0X83 && Buffer[4] == 0x20 && Buffer[5] == 0x00)
    // if (Buffer[0] == 0X5A )
    {
    for (int i = 0; i <= 8; i++)  //this loop will store whole frame in buffer array.
    {
    Serial.print(" 0x");
    Serial.print(Buffer[i], HEX);
    }
    Serial.println("");
    switch (Buffer[7]) {
    case 0x01:  //for pour
    if (Buffer[8] == 0x00) {
    Serial.println("Pour: Old Fashioned");
    drinktype = "oldfashioned";
    return_code = 1;
    } else if (Buffer[8] == 0x01) {
    Serial.println("Pour: Bourbon Shot");
    drinktype = "bourbonshot";
    return_code = 1;
    } else if (Buffer[8] == 0x02) {
    Serial.println("Pour: Vodka Shot");
    drinktype = "vodkashot";
    return_code = 1;
    } else {
    Serial.println("Pour: Unknown Drink");
    }
    break;
    case 0x02:  //for setup
    if (Buffer[8] == 0x00) {
    Serial.println("Setup: Purge");
    purge();
    } else if (Buffer[8] == 0x01) {
    Serial.println("Setup: Clean");
    clean();
    } else if (Buffer[8] == 0x02) {
    Serial.println("Setup: Prime");
    prime();
    } else if (Buffer[8] == 0x03) {
    Serial.println("Setup: Resert Counters");
    reset_counters();
    } else if (Buffer[8] == 0x04) {
    Serial.println("Setup: Toggle Game");
    SS_enabled = !SS_enabled;
    if (SS_enabled) {
    set_top_icon(1, 2);
    } else {
    set_top_icon(1, 3);
    }
    } else {
    Serial.println("Setup: Unknown Requestd");
    }
    break;
    default:
    Serial.println("Unknown Command Code");
    }
    }
    }
    return return_code;
    }
    unsigned char get_button_press() {
    unsigned char Buffer[9];
    if (dwin.available()) {
    for (int i = 0; i <= 8; i++)  //this loop will store whole frame in buffer array.
    {
    Buffer[i] = dwin.read();
    }
    if (Buffer[0] == 0X5A && Buffer[1] == 0XA5 && Buffer[3] == 0X83 && Buffer[4] == 0x22 && Buffer[5] == 0x10)
    // if (Buffer[0] == 0X5A )
    {
    for (int i = 0; i <= 8; i++)  //this loop will store whole frame in buffer array.
    {
    Serial.print(" 0x");
    Serial.print(Buffer[i], HEX);
    }
    Serial.println("");
    unsigned char ClearButton[8] = { 0x5a, 0xa5, 0x05, 0x82, 0x22, 0x10, 0x00, 0x00 };
    dwin.write(ClearButton, 8);
    return Buffer[8];
    }
    }
    return 0x00;
    }
    void clear_touch_serial_buffer() {
    unsigned char Buffer[9];
    if (dwin.available()) {
    for (int i = 0; i <= 8; i++)  //this loop will store whole frame in buffer array.
    {
    Buffer[i] = dwin.read();
    }
    }
    }
    void set_touch_progress(unsigned char progress_percent) {
    unsigned char ProgressBar[8] = { 0x5a, 0xa5, 0x05, 0x82, 0x20, 0x04, 0x00, 0x00 };
    ProgressBar[6] = 0x00;
    ProgressBar[7] = progress_percent;
    dwin.write(ProgressBar, 8);
    }
    void set_touch_numdrinks(unsigned char num_drinks) {
    unsigned char NumDrinks[8] = { 0x5a, 0xa5, 0x05, 0x82, 0x20, 0x08, 0x00, 0x00 };
    NumDrinks[6] = 0x00;
    NumDrinks[7] = num_drinks;
    dwin.write(NumDrinks, 8);
    }
    void set_touch_page(unsigned char page) {
    unsigned char Page[10] = { 0x5a, 0xa5, 0x07, 0x82, 0x00, 0x84, 0x5a, 0x01, 0x00, 0x00 };
    Page[8] = 0x00;
    Page[9] = page;
    dwin.write(Page, 10);
    }
    void reset_touch_screen() {
    unsigned char ResetCommand[10] = { 0x5a, 0xa5, 0x07, 0x82, 0x00, 0x04, 0x55, 0xaa, 0x5a, 0xa5 };
    unsigned char ProgressBar[8] = { 0x5a, 0xa5, 0x05, 0x82, 0x20, 0x04, 0x00, 0x00 };
    dwin.write(ResetCommand, 10);
    dwin.write(ProgressBar, 8);
    }
    void set_top_icon(unsigned char id, unsigned char value) {
    unsigned char Icon[8] = { 0x5a, 0xa5, 0x05, 0x82, 0x21, 0x00, 0x00, 0x00 };
    Icon[5] = Icon[5] + (id * 4);
    Icon[6] = 0x00;
    Icon[7] = value;
    dwin.write(Icon, 8);
    }
    void set_game_light(unsigned char id, unsigned char value) {
    unsigned char Icon[8] = { 0x5a, 0xa5, 0x05, 0x82, 0x22, 0x00, 0x00, 0x00 };
    Icon[5] = Icon[5] + (id * 4);
    Icon[6] = 0x00;
    Icon[7] = value;
    dwin.write(Icon, 8);
    }
    void set_status_text(char text[]) {
    //6  + 25
    unsigned char Status[56] = { 0x5a, 0xa5, 53, 0x82, 0x40, 0x00 };
    int hit_null = 0;
    for (int i = 0; i < 50; i++) {
    if (hit_null) {
    Status[6 + i] = 0;
    } else {
    Status[6 + i] = text[i];
    if (text[i] == 0) {
    hit_null = 1;
    }
    }
    }
    //for (int i = 0; i < 31; i++) {
    //  char  temp_string[3];
    //  sprintf(temp_string, "%02x ", Status[i]);
    //  Serial.print( temp_string );
    // }
    //log_d("");
    dwin.write(Status, 56);
    }
    

    The Business Journey: From Prototype to Production-Ready

    Bar BEE Tender was more than just a technical challenge; it was an exercise in entrepreneurship. I treated this project as a startup, navigating every stage of the business development lifecycle.

    Intellectual Property: To protect the unique concept, I successfully filed for:

    • A Provisional Patent with the U.S. Patent and Trademark Office (USPTO), detailing the novel integration of a memory game with an automated dispensing system.
    • A Trademark for the “Bar BEE Tender” name and brand.

    Go-to-Market Strategy: My goal was to launch Bar BEE Tender on Kickstarter. To prepare for this, I developed a comprehensive business plan and marketing collateral, outlining the target market, competitive landscape, and financial projections.

    Manufacturing & Supply Chain: I initiated discussions with a manufacturing broker in China to source components and plan for mass production. This involved creating a Bill of Materials (BOM), estimating costs, and beginning the design for manufacturing (DFM) process for the first production unit. Since this was a at home applicate reliably was critical to ensure that the brand was not tarnished by defective product. In addition to the physical hardware I started to build a team to take my prototype and harden the cloud infrastructure and mobile app. I told the distributed team that we need it so simple that my grandmother can set it up and use it. I was working with a US based distributor to provide drop shipping services and product support.

    The Vision for the Future 🚀

    While the prototype focused on perfecting the core experience, there was a robust roadmap to evolve Bar BEE Tender from a smart cocktail machine into a fully interactive entertainment platform. The goal was to deepen user engagement through software updates and expanded connectivity.

    An Arcade of Bar Games

    The “Simon” game was just the beginning. The next step was to build a library of games that could be selected via the touchscreen or mobile app.

    • Cocktail Trivia: Imagine this: the screen presents a trivia question about spirits or cocktail history. Players would submit their answers through their smartphones. A correct answer would be rewarded with the machine pouring a drink.
    • Reaction Challenges: A fast-paced game where users have to tap colors or shapes on the screen as quickly as possible. Faster times would unlock a “perfect pour.”

    Networked & Social Gameplay

    The true centerpiece of the future vision was multi-device connectivity. By enabling two or more Bar BEE Tender machines on the same Wi-Fi network to communicate, we could have created truly social, competitive experiences.

    • Head-to-Head “Simon”: Two players could compete simultaneously on separate devices, racing to see who could complete the longest sequence first.
    • Team Trivia: A group could be split into two teams, with each Bar BEE Tender representing a team’s station. Correct answers from the team would contribute to earning the next round of drinks.

    A Customizable Digital Mixologist

    The most significant planned upgrade was a comprehensive recipe management system powered by the companion mobile app. This would have transformed the device from a single-drink dispenser into a versatile robotic bartender.

    • Recipe Creator & Browser: Users could use the app to browse a library of classic cocktail recipes or create and save their own custom concoctions by specifying the ingredients and their exact ratios.
    • “Upload to Bar BEE”: With a single tap, a user could send any recipe from their phone to the machine. Bar BEE Tender would then automatically adjust its pouring logic to craft the new drink perfectly.
    • Smart Inventory: The app would also track the volume of each ingredient, sending a notification when a bottle was running low and even suggesting cocktails that could be made with the remaining ingredients.

    Project Conclusion: A Journey Paused

    Due to a major life-changing event, I was unfortunately forced to put the Bar BEE Tender project on hold before its planned Kickstarter launch. While it was a difficult decision, the journey was an invaluable experience.

    This project demonstrates my ability to take a complex idea from a simple concept to a functional hardware prototype, a polished software experience, and a viable business plan. It showcases my skills in hardware engineering, software development, IoT integration, mobile app creation, and the strategic planning required to bring a product to market.

    Though Bar BEE Tender never made its public debut, it stands as a testament to my passion for innovation, my technical capabilities, and my drive to build something truly unique.

  • The Power of Iteration: My Pinewood Derby Journey

    Ever heard the saying, “If at first you don’t succeed, try, try again”? It’s a cliché for a reason, especially when it comes to product development. The journey from a great idea to a tangible, functional product is rarely a straight line. More often, it’s a series of small steps, tests, and refinements – a process known as iteration.

    When you’re developing something new, it’s easy to get caught up in the desire for perfection from the outset. We want the first version to be the version, flawless and ready for prime time. But the reality is, true innovation and robust design come from embracing imperfection and the learning that comes with it.

    Think of it like this: you have an idea, you build a prototype (even a rough one), you test it, you learn what works and what doesn’t, and then you make a small, focused change. You don’t scrap the whole thing and start over; you refine. You iterate.

    I experienced this firsthand when I decided to learn Computer-Aided Design (CAD). What better way to learn a new skill than by tackling a fun, slightly over-engineered project? My goal was to design a Pinewood Derby car, but not just any car. This one would have a microcontroller and a fan motor mounted on top – a truly ambitious, and perhaps slightly absurd, addition to a traditional gravity-powered race car.

    My initial designs in CAD were, let’s just say, optimistic. I’d spend hours meticulously crafting what I thought was the perfect body, only to print it and realize that the fan motor didn’t fit quite right, or the weight distribution was completely off, or the aesthetic was just… not there.

    Instead of getting discouraged, I leaned into the iterative process. Each print was a learning opportunity.

    Here are all seven versions of the car body I printed throughout my design journey:

    You can see the progression!

    • Version 1 was just getting the basic shape down, learning two axis shapes in CAD.
    • Version 2 stated to curve the sides.
    • Versions 3, 4 and 5 dealt with fitting fan and figuring out the best was to connect it.
    • Version 6 adding a location for the wheels to mount, making sure the cavity can fit the battery and microcontroller and fitting the top and bottom.
    • And finally, Version 7 (the one with the electronics mounted) was the culmination – a design where everything fit, looked good, and was ready for the track (or at least, ready to look cool on a shelf after the race!).

    Each iteration wasn’t a failure, but a step forward. Each physical model in my hand allowed me to see flaws that weren’t apparent on a screen. I could feel the weight, test the clearances, and visualize the final product in a way that CAD alone couldn’t provide.

    This experience solidified my belief in the iterative approach to any development process, whether it’s learning a new software, designing a complex product, or even writing a blog post.

    Key Takeaways for Your Next Project:

    1. Start Small, Learn Fast: Don’t aim for the magnum opus on your first try. Get a basic version out there as quickly as possible.
    2. Test Relentlessly: Every change, no matter how minor, should be followed by a test. This is where you gather crucial feedback.
    3. Embrace “Failure” as Feedback: If something doesn’t work, that’s not a setback; it’s data. It tells you what to change next.
    4. Make Incremental Changes: Avoid overhauling everything at once. Small, focused adjustments make it easier to pinpoint what’s working and what’s not.
    5. Document Your Journey: Like my collection of car bodies, keeping track of your iterations helps you see your progress and learn from past attempts.

    So, the next time you’re faced with a challenge in product development, or really, any complex task, remember my Pinewood Derby car. Don’t seek perfection immediately. Instead, embrace the journey of iteration – make a change, test it, learn, and repeat. It’s the most effective path to success.

  • Guided by Giants: Unveiling Inner Wisdom with Business Coaching

    The phrase “Standing on the shoulders of giants,” a concept I first encountered in engineering school, transcends its initial context to offer profound wisdom in the business world. In my journey with business coaching, this principle has been a guiding light, teaching me to build upon the accumulated wisdom of past business leaders and thinkers. This philosophy underlines the importance of learning from history to forge a successful future in business and life. Along with learning from our past teachers, a coach like Dave Kinnear helps you see your inner wisdom and provides guidance to tap into your own wisdom, reshaping your perspective on career, family, and life. It’s a journey of discovery and rediscovery, where a coach like Dave acts as a mirror, reflecting your innate wisdom and understanding while providing insight from our past teachers.

    The Role of a Business Coach

    Business coaches are more than advisors; they are facilitators of self-awareness. Their skill lies in guiding you to uncover and utilize the knowledge and insights you possess, helping you navigate personal and professional landscapes.

    Uncovering Hidden Insights

    1. Reflective Problem-Solving: Coaches lead you to use your own experiences and knowledge to solve problems creatively.
    2. Harnessing Personal Experiences: By reflecting on past experiences, coaches help you find wisdom in your own journey, viewing adversities as learning opportunities.
    3. Balancing Life with Inner Knowledge: Coaches assist in recognizing and aligning your career and family life based on your values and beliefs.

    The Process of Self-Discovery

    • Self-Assessment and Realization: Identifying your strengths, weaknesses, and innate abilities through introspection.
    • Goal Setting Based on Self-Knowledge: Setting realistic goals that align with your personal insights and aspirations.
    • Sustained Growth and Accountability: Regular sessions with a coach provide a structured approach to personal and professional development.

    The Path of Learning from Past Masters

    • Reflecting on Past Teachings: Gaining insight from the wisdom and experiences of previous educators and mentors.
    • Setting Aspirational Goals Inspired by Predecessors: Formulating ambitions influenced by the achievements and teachings of those who paved the way.
    • Continual Advancement and Reverence: Consistently engaging in learning and development, acknowledging and building upon the foundational work of past giants in your field of interest.

    The transformative power of a business coach like Dave Kinnear lies in their ability to help you tap into and utilize your own knowledge and experiences. This journey of self-discovery and reflection has reshaped how I approach all aspects of life. Far from being a mere advisory service, business coaching is about uncovering the wisdom you already possess guiding you towards realizing your full potential.

    Thank you, Dave, for your insights and knowledge transforming my perspective and life.

  • The Compass of Success: Defining Our Vision and the Role of Values

    In the dynamic and often unpredictable world of business, navigating toward success requires more than just a destination; it requires a compass. Today, I want to delve into the essence of what guides us as a team: our Vision and the pivotal role of Values. These aren’t mere buzzwords; they’re the pillars upon which we build our journey.


    Our Vision – The Destination We Seek

    Picture a ship setting sail without a destination. It wanders aimlessly, at the mercy of the winds and tides. Our Vision is the antithesis of this; it is our chosen destination, the beacon towards which we steer all our efforts. It represents our collective aspirations, our goals, and the impact we aim to make. This Vision serves as our strategic roadmap, guiding each decision and propelling us forward with purpose.

    Defining Values – Our Moral Compass

    Now, let’s talk about Values. What are they? Values are the fundamental beliefs that guide our behaviors and decision-making processes. They are the moral compass that keeps us aligned with our Vision. Values are the guardrails that ensure we stay true to our ethos, no matter the challenges we encounter.

    Imagine Values as the stars by which ancient sailors navigated. Each value is a star, providing direction and keeping the ship on course. They are the principles that dictate how we operate, interact, and make choices. Values are what anchor us to our Vision, ensuring that our journey is not only successful but also ethical and meaningful.


    The Interplay of Vision and Values

    The relationship between Vision and Values is symbiotic. While our Vision sets the destination, our Values determine how we get there. They ensure that in our pursuit of success, we don’t lose sight of who we are and what we stand for. In moments of uncertainty or ethical dilemmas, it’s our Values that offer clarity and guidance.


    Embracing the Journey

    As we sail the seas of our industry, our Vision and Values are our constant companions. They remind us that the journey is as important as the destination. They inspire us to make decisions that aren’t just beneficial but are also aligned with our core beliefs. It’s this combination of a clear Vision and strong Values that paves the way for sustainable success.


    Our Vision and Values are more than strategic tools; they are a reflection of our identity. They are what sets us apart, what drives our passion, and what ensures that our journey is as commendable as our achievements. Join us on this voyage, where our Vision sets the destination, and our Values light the way.

    #TeamVision #CoreValues #Leadership #SustainableSuccess

  • Fostering Long-Term Growth in Your Team: A Personal Leadership Philosophy

    I was inspired to write this when Instagram reminded me about Steve Jobs’s conversation in 1992 with MIT students where he was asked, “What is the most important thing that you personally learned at Apple….?”  He answered, after a long, thoughtful pause, “….I now take a longer-term view on people….”

    Over the years, I’ve come to realize the immense value of looking at team members not just as employees but as long-term partners in success. This approach has profoundly shaped my leadership style and how I envision the growth of my organization. Here are some key lessons I’ve learned along the way.

    Encouraging Growth Rather Than Just Fixing Mistakes

    Early in my career, I often found myself stepping in to correct mistakes. However, I’ve learned that a more sustainable approach is to help team members learn and grow from their experiences. This means viewing errors not as setbacks but as opportunities for development. It’s a shift from a quick-fix mentality to a growth-oriented mindset.

    Collaborative Decision-Making

    In my team, we practice a collaborative approach to significant decisions. This doesn’t mean that every decision is made by committee, but I believe in the power of collective wisdom for those critical choices. This approach takes patience, but decisions are often more comprehensive and effective.

    It takes trust from everyone to grow.

    Trust and Value in the Team

    I strongly believe in trusting the expertise of my team. By actively seeking their advice and valuing their opinions, I foster a culture where everyone feels heard and respected. This leads to better decision-making and creates a more engaged and motivated team.

    Diplomacy in Conflict Resolution

    Conflicts are natural, but how they are handled makes all the difference. I advocate for a diplomatic approach, facilitating conversations where differing viewpoints can be expressed and understood. This method resolves conflicts and often leads to stronger relationships and better solutions.

    Making Tough Decisions

    Leadership has its hard choices. There have been times when I’ve had to make tough calls for the team’s and the organization’s health. These decisions are never easy, but sometimes they are necessary for the team’s overall growth.


    Adopting a long-term perspective of your team members is about more than patience; it’s about nurturing a culture where growth, collaboration, respect, and trust are paramount. This philosophy doesn’t just prepare us for immediate challenges; it sets us up for enduring success. Remember, we’re not just building a team for today; we’re cultivating leaders and innovators for the future.

  • The Crucial Role of Trust in High-Performing Teams of Knowledge Workers

    In today’s fast-paced and ever-evolving work environment, teams of knowledge workers are at the forefront of innovation, problem-solving, and driving organizational success. However, the success of these teams hinges on a critical factor that often goes unnoticed but plays a pivotal role: trust. Trust is not merely about reliability; it’s about believing that your team members genuinely have your best interests in mind. This article will explore why trust is so critical for knowledge-worker teams.

    Trust as “I know that you know I have your best interests in mind.”

    This definition of trust encapsulates the essence of what makes it indispensable in a team of knowledge workers. Let’s break it down:

    1. Mutual Understanding: Trust begins with a mutual understanding that team members are working towards common goals. In a knowledge worker team, everyone must believe that their colleagues share the same commitment to achieving excellence.
    2. Emotional Safety: Knowledge workers often deal with complex tasks that require creative problem-solving and innovation. They need to feel emotionally safe within their team to take risks and think outside the box. Trust creates a safe environment where team members are not afraid to voice their ideas, concerns, or doubts.
    3. Collaboration and Innovation: Trust fosters collaboration. When team members know that their peers genuinely care about their success and well-being, they are more likely to collaborate openly, share knowledge, and co-create innovative solutions.
    4. Conflict Resolution: Trust acts as a buffer during conflicts or disagreements. In a high-trust environment, team members can address conflicts constructively, knowing that disagreements are not personal attacks but opportunities for growth and improvement.
    5. Productivity and Accountability: When trust is high, there’s a sense of shared responsibility for the team’s success. Team members are more likely to hold themselves accountable for their actions because they know their colleagues depend on them.

    Why Trust Matters for Knowledge Worker Teams

    1. Enhanced Productivity: Trust reduces the need for micromanagement and allows team members to work independently, knowing that their colleagues will support them when needed. This autonomy leads to increased productivity.
    2. Attraction and Retention of Talent: Knowledge workers are drawn to organizations and teams where they feel trusted and valued. Furthermore, high trust levels within a team increase employee retention rates.
    3. Innovation and Problem-Solving: In a high-trust environment, knowledge workers are more likely to share unconventional ideas and take calculated risks, leading to breakthrough innovations and creative solutions.
    4. Adaptability: Trust enables teams to adapt quickly to changing circumstances and challenges. When team members trust each other’s judgment and intentions, they can confidently pivot and embrace new approaches.
    5. Stress Reduction: Trust reduces workplace stress. When team members know they have the support of their colleagues, they can manage their workload more effectively, reducing burnout and increasing job satisfaction.

    Fostering Trust in Knowledge Worker Teams

    Building trust in a team of knowledge workers takes time. It requires continuous effort and a commitment to cultivating a culture of trust. Here are some strategies:

    1. Lead by Example: Leaders should set the tone by demonstrating trust in their team members’ abilities and intentions.
    2. Effective Communication: Encourage open and honest communication within the team. Ensure that everyone has a voice and is heard.
    3. Transparency: Be transparent about decisions and their rationale, especially in situations that directly impact the team.
    4. Recognition and Appreciation: Recognize and appreciate the contributions of team members. A simple “thank you” can go a long way in building trust.
    5. Conflict Resolution Training: Provide training on constructive conflict resolution to help team members address issues in a healthy manner.

    Trust is not a soft or intangible concept but a fundamental pillar of success for teams of knowledge workers. When team members trust that their colleagues genuinely have their best interests in mind, they can achieve remarkable feats, drive innovation, and navigate the complex challenges of the modern workplace with confidence and resilience. Building and nurturing trust should be a top priority for any team that aspires to reach its full potential.