We play with technology. Sometimes we discover things we think are worth sharing.

Download: arduino_-_from_ino_to_python.zip

Downloading: arduino_-_from_ino_to_python.zip Arduino - From INO to Python



***
<style>
kbd {
    color: black;
    padding: .1em .6em;
    font-size: 11px;
    background-color: #e4e6e8;
    border: 1px solid #9fa6ad;
    border-radius: 3px;
    box-shadow: 0 1px 1px rgba(12,13,14,0.15),inset 0 1px 0 0 white;
    white-space: nowrap;
}
</style>

# Introduction

The Arduino is a board that runs a compiled version of INO (C++), in this guide you will learn how to program the Arduino and use more complex things such as serial and Firmata.

## IDE

[Download page](https://www.arduino.cc/en/software 'arduino.cc')

Key:
![arduinoide.jpg](https://blog.abbey1.org.uk/media/blogs/technology/quick-uploads/arduino/arduinoide.jpg "arduinoide")

***

# First Circuits

## Light the Lamp

Light the Lamp is the simplest circuit; it involves turning on 1 LED.
Unplug the USB cable and build this circuit:

![lightthelamp.jpg](https://blog.abbey1.org.uk/media/blogs/technology/quick-uploads/arduino/lightthelamp.jpg "lightthelamp")

If all goes to plan when you connect the USB cable again the LED should turn on. **Take note of how things are connected up.**

## Blink

Blink is a circuit that makes the LED flip between on and off.
Unplug the USB cable and build this circuit:

![blink.jpg](https://blog.abbey1.org.uk/media/blogs/technology/quick-uploads/arduino/blink.jpg "blink")

Now this circuit won't just work when you plug it in we need to program the Arduino board.
So plug-in your board and boot up the Arduino software.
When you load into your Arduino software, you should see a text editing window that contains:

```arduino
void setup() {
    // put your setup code here, to run once:

}

void loop() {
    // put your main code here, to run repeatedly:

}
```

If so you should swap it out for:

```arduino
// create a variable containing the pin number that the LED is connected to
int led = 13;

void setup() {
  // Set the LED pin to OUTPUT
  pinMode(led, OUTPUT);
}

void loop() {
  // Set the LED pin to HIGH (or on)
  digitalWrite(led, HIGH);

  // Wait for 1 second (1000ms)
  delay(1000);

  // Set the LED pin to LOW (or off)
  digitalWrite(led, LOW);

  // Wait for 1 second (1000ms)
  delay(1000);
}
```

Hit the upload button, and the LED should start to toggle every second.

### Diagram
```mermaid
graph TD
    A{Start}
    A-->B(set 'led' to 13)
    B-->C(set 'led' 'pinmode' to output)
    C-->D(turn 'led' on)
    D-->E(wait 1 second)
    E-->F(turn 'led' off)
    F-->G(wait 1 second)
    G-->D
    subgraph setup
        C
    end
    subgraph loop
        D
        E
        F
        G
    end
```

## Analog and Serial

### Analog

The Arduino UNO has 2 types of pin digital and analog; digital pins can be on or off (they can be also be PWM but that will be covered later on) where as analog pins can output a signal between 0 and 1023 (it is actually 0 and 1 but the Arduino code use 0 and 1023).

### Serial

Serial is a means by which you can send data over a cable; it is necessary because a USB 2.0 cable, like the one connecting your Arduino and computer, only has 2 data wires which without serial would only be able to represent a number between 0 and 3.

### Example

Circuit:
![analogandserial.jpg](https://blog.abbey1.org.uk/media/blogs/technology/quick-uploads/arduino/analogandserial.jpg "analogandserial")

Code:
```arduino
int analogInPin = A0; // Analog input pin that the potentiometer is attached to

int sensorValue = 0; // value read from the pot
int outputValue = 0; // value output to the PWM (analog out)

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
}

void loop() {
  // read the analog in value:
  sensorValue = analogRead(analogInPin);
  // map it to the range of the analog out:
  outputValue = map(sensorValue, 0, 1023, 0, 255);

  // print the results to the Serial Monitor:
  Serial.print("sensor = ");
  Serial.print(sensorValue);
  Serial.print("\t output = ");
  Serial.println(outputValue);

  // wait 2 milliseconds before the next loop for the analog-to-digital
  // converter to settle after the last reading:
  delay(2);
}
```

Once you have built the circuit and uploaded the code onto the Arduino, open up the serial monitor (the button is marked on [HERE](//blog.abbey1.org.uk/index.php/technology/arduino#ide-integrated-development-environment#ide-integrated-development-environment "IDE")). As you turn the potentiometer (knob), the LED's brightness should change and the values in the serial monitor should change. **At this point it is very important that you look back and make sure you understand why things do what they do.**

***

# Serial and Firmata

## Firmata

### What is "Firmata"?

Firmata is a protocol for communication over serial (USB, Bluetooth and WiFi); it gives access to commands that control the pins, importantly it has bindings in python.

### Setup

In this tutorial we will be using python so we need to install the module "pyfirmata2":
```shell
# Python2
# Debian and Ubuntu
apt install python-pyfirmata2

# Windows, OSX and other PIP
pip install pyfirmata2

# Python3
# Debian and Ubuntu
apt install python3-pyfirmata2

# Windows, OSX and other PIP
pip3 install pyfirmata2
```

For this program you will need to install the Firmata Plugin, to install it press ctrl + shift + i or command + shift + i on OSX to bring up the library manager. Then search for "Firmata" (I have version 2.5.8) and install it.
We also need to load the "standard firmata" program onto the arduino, It can be loaded through the menu or the code I have provided below.
![firmata.png](https://blog.abbey1.org.uk/media/blogs/technology/quick-uploads/arduino/firmata.png "firmata")
```arduino
/*
  Firmata is a generic protocol for communicating with microcontrollers
  from software on a host computer. It is intended to work with
  any host computer software package.

  To download a host software package, please click on the following link
  to open the list of Firmata client libraries in your default browser.

  https://github.com/firmata/arduino#firmata-client-libraries

  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.
  Copyright (C) 2010-2011 Paul Stoffregen.  All rights reserved.
  Copyright (C) 2009 Shigeru Kobayashi.  All rights reserved.
  Copyright (C) 2009-2016 Jeff Hoefs.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  See file LICENSE.txt for further informations on licensing terms.

  Last updated August 17th, 2017
*/

#include <Servo.h>
#include <Wire.h>
#include <Firmata.h>

#define I2C_WRITE                   B00000000
#define I2C_READ                    B00001000
#define I2C_READ_CONTINUOUSLY       B00010000
#define I2C_STOP_READING            B00011000
#define I2C_READ_WRITE_MODE_MASK    B00011000
#define I2C_10BIT_ADDRESS_MODE_MASK B00100000
#define I2C_END_TX_MASK             B01000000
#define I2C_STOP_TX                 1
#define I2C_RESTART_TX              0
#define I2C_MAX_QUERIES             8
#define I2C_REGISTER_NOT_SPECIFIED  -1

// the minimum interval for sampling analog input
#define MINIMUM_SAMPLING_INTERVAL   1


/*==============================================================================
 * GLOBAL VARIABLES
 *============================================================================*/

#ifdef FIRMATA_SERIAL_FEATURE
SerialFirmata serialFeature;
#endif

/* analog inputs */
int analogInputsToReport = 0; // bitwise array to store pin reporting

/* digital input ports */
byte reportPINs[TOTAL_PORTS];       // 1 = report this port, 0 = silence
byte previousPINs[TOTAL_PORTS];     // previous 8 bits sent

/* pins configuration */
byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else

/* timer variables */
unsigned long currentMillis;        // store the current value from millis()
unsigned long previousMillis;       // for comparison with currentMillis
unsigned int samplingInterval = 19; // how often to run the main loop (in ms)

/* i2c data */
struct i2c_device_info {
  byte addr;
  int reg;
  byte bytes;
  byte stopTX;
};

/* for i2c read continuous more */
i2c_device_info query[I2C_MAX_QUERIES];

byte i2cRxData[64];
boolean isI2CEnabled = false;
signed char queryIndex = -1;
// default delay time between i2c read request and Wire.requestFrom()
unsigned int i2cReadDelayTime = 0;

Servo servos[MAX_SERVOS];
byte servoPinMap[TOTAL_PINS];
byte detachedServos[MAX_SERVOS];
byte detachedServoCount = 0;
byte servoCount = 0;

boolean isResetting = false;

// Forward declare a few functions to avoid compiler errors with older versions
// of the Arduino IDE.
void setPinModeCallback(byte, int);
void reportAnalogCallback(byte analogPin, int value);
void sysexCallback(byte, byte, byte*);

/* utility functions */
void wireWrite(byte data)
{
#if ARDUINO >= 100
  Wire.write((byte)data);
#else
  Wire.send(data);
#endif
}

byte wireRead(void)
{
#if ARDUINO >= 100
  return Wire.read();
#else
  return Wire.receive();
#endif
}

/*==============================================================================
 * FUNCTIONS
 *============================================================================*/

void attachServo(byte pin, int minPulse, int maxPulse)
{
  if (servoCount < MAX_SERVOS) {
    // reuse indexes of detached servos until all have been reallocated
    if (detachedServoCount > 0) {
      servoPinMap[pin] = detachedServos[detachedServoCount - 1];
      if (detachedServoCount > 0) detachedServoCount--;
    } else {
      servoPinMap[pin] = servoCount;
      servoCount++;
    }
    if (minPulse > 0 && maxPulse > 0) {
      servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse);
    } else {
      servos[servoPinMap[pin]].attach(PIN_TO_DIGITAL(pin));
    }
  } else {
    Firmata.sendString("Max servos attached");
  }
}

void detachServo(byte pin)
{
  servos[servoPinMap[pin]].detach();
  // if we're detaching the last servo, decrement the count
  // otherwise store the index of the detached servo
  if (servoPinMap[pin] == servoCount && servoCount > 0) {
    servoCount--;
  } else if (servoCount > 0) {
    // keep track of detached servos because we want to reuse their indexes
    // before incrementing the count of attached servos
    detachedServoCount++;
    detachedServos[detachedServoCount - 1] = servoPinMap[pin];
  }

  servoPinMap[pin] = 255;
}

void enableI2CPins()
{
  byte i;
  // is there a faster way to do this? would probaby require importing
  // Arduino.h to get SCL and SDA pins
  for (i = 0; i < TOTAL_PINS; i++) {
    if (IS_PIN_I2C(i)) {
      // mark pins as i2c so they are ignore in non i2c data requests
      setPinModeCallback(i, PIN_MODE_I2C);
    }
  }

  isI2CEnabled = true;

  Wire.begin();
}

/* disable the i2c pins so they can be used for other functions */
void disableI2CPins() {
  isI2CEnabled = false;
  // disable read continuous mode for all devices
  queryIndex = -1;
}

void readAndReportData(byte address, int theRegister, byte numBytes, byte stopTX) {
  // allow I2C requests that don't require a register read
  // for example, some devices using an interrupt pin to signify new data available
  // do not always require the register read so upon interrupt you call Wire.requestFrom()
  if (theRegister != I2C_REGISTER_NOT_SPECIFIED) {
    Wire.beginTransmission(address);
    wireWrite((byte)theRegister);
    Wire.endTransmission(stopTX); // default = true
    // do not set a value of 0
    if (i2cReadDelayTime > 0) {
      // delay is necessary for some devices such as WiiNunchuck
      delayMicroseconds(i2cReadDelayTime);
    }
  } else {
    theRegister = 0;  // fill the register with a dummy value
  }

  Wire.requestFrom(address, numBytes);  // all bytes are returned in requestFrom

  // check to be sure correct number of bytes were returned by slave
  if (numBytes < Wire.available()) {
    Firmata.sendString("I2C: Too many bytes received");
  } else if (numBytes > Wire.available()) {
    Firmata.sendString("I2C: Too few bytes received");
  }

  i2cRxData[0] = address;
  i2cRxData[1] = theRegister;

  for (int i = 0; i < numBytes && Wire.available(); i++) {
    i2cRxData[2 + i] = wireRead();
  }

  // send slave address, register and received bytes
  Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData);
}

void outputPort(byte portNumber, byte portValue, byte forceSend)
{
  // pins not configured as INPUT are cleared to zeros
  portValue = portValue & portConfigInputs[portNumber];
  // only send if the value is different than previously sent
  if (forceSend || previousPINs[portNumber] != portValue) {
    Firmata.sendDigitalPort(portNumber, portValue);
    previousPINs[portNumber] = portValue;
  }
}

/* -----------------------------------------------------------------------------
 * check all the active digital inputs for change of state, then add any events
 * to the Serial output queue using Serial.print() */
void checkDigitalInputs(void)
{
  /* Using non-looping code allows constants to be given to readPort().
   * The compiler will apply substantial optimizations if the inputs
   * to readPort() are compile-time constants. */
  if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false);
  if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
  if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false);
  if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
  if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
  if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
  if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
  if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
  if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
  if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
  if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
  if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
  if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
  if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
  if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
  if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
}

// -----------------------------------------------------------------------------
/* sets the pin mode to the correct state and sets the relevant bits in the
 * two bit-arrays that track Digital I/O and PWM status
 */
void setPinModeCallback(byte pin, int mode)
{
  if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE)
    return;

  if (Firmata.getPinMode(pin) == PIN_MODE_I2C && isI2CEnabled && mode != PIN_MODE_I2C) {
    // disable i2c so pins can be used for other functions
    // the following if statements should reconfigure the pins properly
    disableI2CPins();
  }
  if (IS_PIN_DIGITAL(pin) && mode != PIN_MODE_SERVO) {
    if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
      detachServo(pin);
    }
  }
  if (IS_PIN_ANALOG(pin)) {
    reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting
  }
  if (IS_PIN_DIGITAL(pin)) {
    if (mode == INPUT || mode == PIN_MODE_PULLUP) {
      portConfigInputs[pin / 8] |= (1 << (pin & 7));
    } else {
      portConfigInputs[pin / 8] &= ~(1 << (pin & 7));
    }
  }
  Firmata.setPinState(pin, 0);
  switch (mode) {
    case PIN_MODE_ANALOG:
      if (IS_PIN_ANALOG(pin)) {
        if (IS_PIN_DIGITAL(pin)) {
          pinMode(PIN_TO_DIGITAL(pin), INPUT);    // disable output driver
#if ARDUINO <= 100
          // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
          digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
#endif
        }
        Firmata.setPinMode(pin, PIN_MODE_ANALOG);
      }
      break;
    case INPUT:
      if (IS_PIN_DIGITAL(pin)) {
        pinMode(PIN_TO_DIGITAL(pin), INPUT);    // disable output driver
#if ARDUINO <= 100
        // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
        digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
#endif
        Firmata.setPinMode(pin, INPUT);
      }
      break;
    case PIN_MODE_PULLUP:
      if (IS_PIN_DIGITAL(pin)) {
        pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP);
        Firmata.setPinMode(pin, PIN_MODE_PULLUP);
        Firmata.setPinState(pin, 1);
      }
      break;
    case OUTPUT:
      if (IS_PIN_DIGITAL(pin)) {
        if (Firmata.getPinMode(pin) == PIN_MODE_PWM) {
          // Disable PWM if pin mode was previously set to PWM.
          digitalWrite(PIN_TO_DIGITAL(pin), LOW);
        }
        pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
        Firmata.setPinMode(pin, OUTPUT);
      }
      break;
    case PIN_MODE_PWM:
      if (IS_PIN_PWM(pin)) {
        pinMode(PIN_TO_PWM(pin), OUTPUT);
        analogWrite(PIN_TO_PWM(pin), 0);
        Firmata.setPinMode(pin, PIN_MODE_PWM);
      }
      break;
    case PIN_MODE_SERVO:
      if (IS_PIN_DIGITAL(pin)) {
        Firmata.setPinMode(pin, PIN_MODE_SERVO);
        if (servoPinMap[pin] == 255 || !servos[servoPinMap[pin]].attached()) {
          // pass -1 for min and max pulse values to use default values set
          // by Servo library
          attachServo(pin, -1, -1);
        }
      }
      break;
    case PIN_MODE_I2C:
      if (IS_PIN_I2C(pin)) {
        // mark the pin as i2c
        // the user must call I2C_CONFIG to enable I2C for a device
        Firmata.setPinMode(pin, PIN_MODE_I2C);
      }
      break;
    case PIN_MODE_SERIAL:
#ifdef FIRMATA_SERIAL_FEATURE
      serialFeature.handlePinMode(pin, PIN_MODE_SERIAL);
#endif
      break;
    default:
      Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
  }
  // TODO: save status to EEPROM here, if changed
}

/*
 * Sets the value of an individual pin. Useful if you want to set a pin value but
 * are not tracking the digital port state.
 * Can only be used on pins configured as OUTPUT.
 * Cannot be used to enable pull-ups on Digital INPUT pins.
 */
void setPinValueCallback(byte pin, int value)
{
  if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) {
    if (Firmata.getPinMode(pin) == OUTPUT) {
      Firmata.setPinState(pin, value);
      digitalWrite(PIN_TO_DIGITAL(pin), value);
    }
  }
}

void analogWriteCallback(byte pin, int value)
{
  if (pin < TOTAL_PINS) {
    switch (Firmata.getPinMode(pin)) {
      case PIN_MODE_SERVO:
        if (IS_PIN_DIGITAL(pin))
          servos[servoPinMap[pin]].write(value);
        Firmata.setPinState(pin, value);
        break;
      case PIN_MODE_PWM:
        if (IS_PIN_PWM(pin))
          analogWrite(PIN_TO_PWM(pin), value);
        Firmata.setPinState(pin, value);
        break;
    }
  }
}

void digitalWriteCallback(byte port, int value)
{
  byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0;

  if (port < TOTAL_PORTS) {
    // create a mask of the pins on this port that are writable.
    lastPin = port * 8 + 8;
    if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS;
    for (pin = port * 8; pin < lastPin; pin++) {
      // do not disturb non-digital pins (eg, Rx & Tx)
      if (IS_PIN_DIGITAL(pin)) {
        // do not touch pins in PWM, ANALOG, SERVO or other modes
        if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) {
          pinValue = ((byte)value & mask) ? 1 : 0;
          if (Firmata.getPinMode(pin) == OUTPUT) {
            pinWriteMask |= mask;
          } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) {
            // only handle INPUT here for backwards compatibility
#if ARDUINO > 100
            pinMode(pin, INPUT_PULLUP);
#else
            // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier
            pinWriteMask |= mask;
#endif
          }
          Firmata.setPinState(pin, pinValue);
        }
      }
      mask = mask << 1;
    }
    writePort(port, (byte)value, pinWriteMask);
  }
}


// -----------------------------------------------------------------------------
/* sets bits in a bit array (int) to toggle the reporting of the analogIns
 */
//void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
//}
void reportAnalogCallback(byte analogPin, int value)
{
  if (analogPin < TOTAL_ANALOG_PINS) {
    if (value == 0) {
      analogInputsToReport = analogInputsToReport & ~ (1 << analogPin);
    } else {
      analogInputsToReport = analogInputsToReport | (1 << analogPin);
      // prevent during system reset or all analog pin values will be reported
      // which may report noise for unconnected analog pins
      if (!isResetting) {
        // Send pin value immediately. This is helpful when connected via
        // ethernet, wi-fi or bluetooth so pin states can be known upon
        // reconnecting.
        Firmata.sendAnalog(analogPin, analogRead(analogPin));
      }
    }
  }
  // TODO: save status to EEPROM here, if changed
}

void reportDigitalCallback(byte port, int value)
{
  if (port < TOTAL_PORTS) {
    reportPINs[port] = (byte)value;
    // Send port value immediately. This is helpful when connected via
    // ethernet, wi-fi or bluetooth so pin states can be known upon
    // reconnecting.
    if (value) outputPort(port, readPort(port, portConfigInputs[port]), true);
  }
  // do not disable analog reporting on these 8 pins, to allow some
  // pins used for digital, others analog.  Instead, allow both types
  // of reporting to be enabled, but check if the pin is configured
  // as analog when sampling the analog inputs.  Likewise, while
  // scanning digital pins, portConfigInputs will mask off values from any
  // pins configured as analog
}

/*==============================================================================
 * SYSEX-BASED commands
 *============================================================================*/

void sysexCallback(byte command, byte argc, byte *argv)
{
  byte mode;
  byte stopTX;
  byte slaveAddress;
  byte data;
  int slaveRegister;
  unsigned int delayTime;

  switch (command) {
    case I2C_REQUEST:
      mode = argv[1] & I2C_READ_WRITE_MODE_MASK;
      if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) {
        Firmata.sendString("10-bit addressing not supported");
        return;
      }
      else {
        slaveAddress = argv[0];
      }

      // need to invert the logic here since 0 will be default for client
      // libraries that have not updated to add support for restart tx
      if (argv[1] & I2C_END_TX_MASK) {
        stopTX = I2C_RESTART_TX;
      }
      else {
        stopTX = I2C_STOP_TX; // default
      }

      switch (mode) {
        case I2C_WRITE:
          Wire.beginTransmission(slaveAddress);
          for (byte i = 2; i < argc; i += 2) {
            data = argv[i] + (argv[i + 1] << 7);
            wireWrite(data);
          }
          Wire.endTransmission();
          delayMicroseconds(70);
          break;
        case I2C_READ:
          if (argc == 6) {
            // a slave register is specified
            slaveRegister = argv[2] + (argv[3] << 7);
            data = argv[4] + (argv[5] << 7);  // bytes to read
          }
          else {
            // a slave register is NOT specified
            slaveRegister = I2C_REGISTER_NOT_SPECIFIED;
            data = argv[2] + (argv[3] << 7);  // bytes to read
          }
          readAndReportData(slaveAddress, (int)slaveRegister, data, stopTX);
          break;
        case I2C_READ_CONTINUOUSLY:
          if ((queryIndex + 1) >= I2C_MAX_QUERIES) {
            // too many queries, just ignore
            Firmata.sendString("too many queries");
            break;
          }
          if (argc == 6) {
            // a slave register is specified
            slaveRegister = argv[2] + (argv[3] << 7);
            data = argv[4] + (argv[5] << 7);  // bytes to read
          }
          else {
            // a slave register is NOT specified
            slaveRegister = (int)I2C_REGISTER_NOT_SPECIFIED;
            data = argv[2] + (argv[3] << 7);  // bytes to read
          }
          queryIndex++;
          query[queryIndex].addr = slaveAddress;
          query[queryIndex].reg = slaveRegister;
          query[queryIndex].bytes = data;
          query[queryIndex].stopTX = stopTX;
          break;
        case I2C_STOP_READING:
          byte queryIndexToSkip;
          // if read continuous mode is enabled for only 1 i2c device, disable
          // read continuous reporting for that device
          if (queryIndex <= 0) {
            queryIndex = -1;
          } else {
            queryIndexToSkip = 0;
            // if read continuous mode is enabled for multiple devices,
            // determine which device to stop reading and remove it's data from
            // the array, shifiting other array data to fill the space
            for (byte i = 0; i < queryIndex + 1; i++) {
              if (query[i].addr == slaveAddress) {
                queryIndexToSkip = i;
                break;
              }
            }

            for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) {
              if (i < I2C_MAX_QUERIES) {
                query[i].addr = query[i + 1].addr;
                query[i].reg = query[i + 1].reg;
                query[i].bytes = query[i + 1].bytes;
                query[i].stopTX = query[i + 1].stopTX;
              }
            }
            queryIndex--;
          }
          break;
        default:
          break;
      }
      break;
    case I2C_CONFIG:
      delayTime = (argv[0] + (argv[1] << 7));

      if (argc > 1 && delayTime > 0) {
        i2cReadDelayTime = delayTime;
      }

      if (!isI2CEnabled) {
        enableI2CPins();
      }

      break;
    case SERVO_CONFIG:
      if (argc > 4) {
        // these vars are here for clarity, they'll optimized away by the compiler
        byte pin = argv[0];
        int minPulse = argv[1] + (argv[2] << 7);
        int maxPulse = argv[3] + (argv[4] << 7);

        if (IS_PIN_DIGITAL(pin)) {
          if (servoPinMap[pin] < MAX_SERVOS && servos[servoPinMap[pin]].attached()) {
            detachServo(pin);
          }
          attachServo(pin, minPulse, maxPulse);
          setPinModeCallback(pin, PIN_MODE_SERVO);
        }
      }
      break;
    case SAMPLING_INTERVAL:
      if (argc > 1) {
        samplingInterval = argv[0] + (argv[1] << 7);
        if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
          samplingInterval = MINIMUM_SAMPLING_INTERVAL;
        }
      } else {
        //Firmata.sendString("Not enough data");
      }
      break;
    case EXTENDED_ANALOG:
      if (argc > 1) {
        int val = argv[1];
        if (argc > 2) val |= (argv[2] << 7);
        if (argc > 3) val |= (argv[3] << 14);
        analogWriteCallback(argv[0], val);
      }
      break;
    case CAPABILITY_QUERY:
      Firmata.write(START_SYSEX);
      Firmata.write(CAPABILITY_RESPONSE);
      for (byte pin = 0; pin < TOTAL_PINS; pin++) {
        if (IS_PIN_DIGITAL(pin)) {
          Firmata.write((byte)INPUT);
          Firmata.write(1);
          Firmata.write((byte)PIN_MODE_PULLUP);
          Firmata.write(1);
          Firmata.write((byte)OUTPUT);
          Firmata.write(1);
        }
        if (IS_PIN_ANALOG(pin)) {
          Firmata.write(PIN_MODE_ANALOG);
          Firmata.write(10); // 10 = 10-bit resolution
        }
        if (IS_PIN_PWM(pin)) {
          Firmata.write(PIN_MODE_PWM);
          Firmata.write(DEFAULT_PWM_RESOLUTION);
        }
        if (IS_PIN_DIGITAL(pin)) {
          Firmata.write(PIN_MODE_SERVO);
          Firmata.write(14);
        }
        if (IS_PIN_I2C(pin)) {
          Firmata.write(PIN_MODE_I2C);
          Firmata.write(1);  // TODO: could assign a number to map to SCL or SDA
        }
#ifdef FIRMATA_SERIAL_FEATURE
        serialFeature.handleCapability(pin);
#endif
        Firmata.write(127);
      }
      Firmata.write(END_SYSEX);
      break;
    case PIN_STATE_QUERY:
      if (argc > 0) {
        byte pin = argv[0];
        Firmata.write(START_SYSEX);
        Firmata.write(PIN_STATE_RESPONSE);
        Firmata.write(pin);
        if (pin < TOTAL_PINS) {
          Firmata.write(Firmata.getPinMode(pin));
          Firmata.write((byte)Firmata.getPinState(pin) & 0x7F);
          if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F);
          if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F);
        }
        Firmata.write(END_SYSEX);
      }
      break;
    case ANALOG_MAPPING_QUERY:
      Firmata.write(START_SYSEX);
      Firmata.write(ANALOG_MAPPING_RESPONSE);
      for (byte pin = 0; pin < TOTAL_PINS; pin++) {
        Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127);
      }
      Firmata.write(END_SYSEX);
      break;

    case SERIAL_MESSAGE:
#ifdef FIRMATA_SERIAL_FEATURE
      serialFeature.handleSysex(command, argc, argv);
#endif
      break;
  }
}

/*==============================================================================
 * SETUP()
 *============================================================================*/

void systemResetCallback()
{
  isResetting = true;

  // initialize a defalt state
  // TODO: option to load config from EEPROM instead of default

#ifdef FIRMATA_SERIAL_FEATURE
  serialFeature.reset();
#endif

  if (isI2CEnabled) {
    disableI2CPins();
  }

  for (byte i = 0; i < TOTAL_PORTS; i++) {
    reportPINs[i] = false;    // by default, reporting off
    portConfigInputs[i] = 0;  // until activated
    previousPINs[i] = 0;
  }

  for (byte i = 0; i < TOTAL_PINS; i++) {
    // pins with analog capability default to analog input
    // otherwise, pins default to digital output
    if (IS_PIN_ANALOG(i)) {
      // turns off pullup, configures everything
      setPinModeCallback(i, PIN_MODE_ANALOG);
    } else if (IS_PIN_DIGITAL(i)) {
      // sets the output to 0, configures portConfigInputs
      setPinModeCallback(i, OUTPUT);
    }

    servoPinMap[i] = 255;
  }
  // by default, do not report any analog inputs
  analogInputsToReport = 0;

  detachedServoCount = 0;
  servoCount = 0;

  /* send digital inputs to set the initial state on the host computer,
   * since once in the loop(), this firmware will only send on change */
  /*
  TODO: this can never execute, since no pins default to digital input
        but it will be needed when/if we support EEPROM stored config
  for (byte i=0; i < TOTAL_PORTS; i++) {
    outputPort(i, readPort(i, portConfigInputs[i]), true);
  }
  */
  isResetting = false;
}

void setup()
{
  Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);

  Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
  Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
  Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
  Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
  Firmata.attach(SET_PIN_MODE, setPinModeCallback);
  Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback);
  Firmata.attach(START_SYSEX, sysexCallback);
  Firmata.attach(SYSTEM_RESET, systemResetCallback);

  // to use a port other than Serial, such as Serial1 on an Arduino Leonardo or Mega,
  // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this:
  // Serial1.begin(57600);
  // Firmata.begin(Serial1);
  // However do not do this if you are using SERIAL_MESSAGE

  Firmata.begin(57600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for ATmega32u4-based boards and Arduino 101
  }

  systemResetCallback();  // reset to default config
}

/*==============================================================================
 * LOOP()
 *============================================================================*/
void loop()
{
  byte pin, analogPin;

  /* DIGITALREAD - as fast as possible, check for changes and output them to the
   * FTDI buffer using Serial.print()  */
  checkDigitalInputs();

  /* STREAMREAD - processing incoming messagse as soon as possible, while still
   * checking digital inputs.  */
  while (Firmata.available())
    Firmata.processInput();

  // TODO - ensure that Stream buffer doesn't go over 60 bytes

  currentMillis = millis();
  if (currentMillis - previousMillis > samplingInterval) {
    previousMillis += samplingInterval;
    /* ANALOGREAD - do all analogReads() at the configured sampling interval */
    for (pin = 0; pin < TOTAL_PINS; pin++) {
      if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) {
        analogPin = PIN_TO_ANALOG(pin);
        if (analogInputsToReport & (1 << analogPin)) {
          Firmata.sendAnalog(analogPin, analogRead(analogPin));
        }
      }
    }
    // report i2c data for all device with read continuous mode enabled
    if (queryIndex > -1) {
      for (byte i = 0; i < queryIndex + 1; i++) {
        readAndReportData(query[i].addr, query[i].reg, query[i].bytes, query[i].stopTX);
      }
    }
  }

#ifdef FIRMATA_SERIAL_FEATURE
  serialFeature.update();
#endif
}
```

### Back to Blink

In back to blink you will rebuild the blink circuit but with python.

Rebuild the blink circuit:

![blink.jpg](https://blog.abbey1.org.uk/media/blogs/technology/quick-uploads/arduino/blink.jpg "blink")

```python
from pyfirmata2 import Arduino
import time

# connect to the board by autodetecting serial ports
board = Arduino(Arduino.AUTODETECT)

# create a variable containing the pin number that the LED is connected to
LED = board.get_pin('d:13:o')

while True:
    # Set the LED pin to HIGH (or on)
    LED.write(1)

    # Wait for 1 second (1000ms)
    time.sleep(1)

    # Set the LED pin to HIGH (or on)
    LED.write(0)

    # Wait for 1 second (1000ms)
    time.sleep(1)
```


Now this is quite boring, what if we wanted to remote control some LEDs.

### Smart LEDs

Smart LEDs is a circuit that allows you to remote control the digital pins of your arduino, which can then be connected to LEDs.

#### Setup the project

Create a folder called "SmartLEDs" or something it doesn't matter.
In the folder create two files "\_\_main\_\_.py" and "httpserver.py".

```folder
{
'__main__.py': `
from pyfirmata2 import Arduino
from httpserver import server

# connect to the board by autodetecting serial ports
board = Arduino(Arduino.AUTODETECT)


# function to run on request
def req(data: str):
    """
    /<set>/<pin>/<value>/          set value
    /<set>/<pin>/                  toggle
    """
    d = data.split("/")
    if d[1] == "favicon.ico":
        return
    print(d)
    try:
        if d[1] == "digital":
            board.digital[int(d[2])].write(int(d[3]))
        elif d[1] == "analog":
            board.analog[int(d[2])].write(int(d[3]))
    except:
        if d[1] == "digital":
            board.digital[int(d[2])].write(not board.digital[int(d[2])].read())
        elif d[1] == "analog":
            board.analog[int(d[2])].write(not board.analog[int(d[2])].read())


# start the http server
server("127.0.0.1", 1234, req)
            `,
'httpserver.py': `import http.server


def default(*args, **kwargs):
    pass


method = default


class handler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        global method
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

        method(self.path)
        self.wfile.write(self.path.encode())


class server:
    def __init__(self, ip, port, handle):
        global method

        self.httpd = http.server.HTTPServer((ip, port), handler)
        method = handle
        self.httpd.serve_forever()`,
}
```

#### What is going on here?

"httpserver.py" is a simple script I wrote to serve a HTTP server with a custom handler.

"\_\_main__.py":

1. import statement for pyfirmata.
2. import statement for httpserver.py.
5) connect to the Arduino.
9. request handling function definition
    10. docstring
    14) split the data (path) into instructions
    15) handle the browser requestion the icon
    17. print data for debug
    18. interact with the pins
    19. check which set was selected
    20. if digital was selected write to the pin
    24) check which set was selected
    25) if digital was selected toggle the pin
31) start the http server

#### Challenge 

Now as a challenge try to rewrite this program to work with sockets.

##### Useful links:

[realpython](https://realpython.com/python-sockets/ 'realpython.com')

[python docs](https://docs.python.org/3/howto/sockets.html 'docs.python.com')


## Liquid Crystal Display

### The circuit

![LCD.jpg](https://blog.abbey1.org.uk/media/blogs/technology/quick-uploads/arduino/lcd.jpg "LCD")

You will need to hook up your LED+/- and VSS/VDD and V0 to power (remember that one of the led pins needs to go through a resistor).

### Basic

In Basic we will get the LCD to display a simple message.

#### Arduino

The Arduino implementation.
For this program you will need to install the LCD Plugin, to install it press &lt;kbd&gt;ctrl&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;i&lt;/kbd&gt; or &lt;kbd&gt;command&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;i&lt;/kbd&gt; on OSX to bring up the library manager. Then search for "LiquidCrystal" (I have version 1.0.7) and install it.

```arduino
#include <LiquidCrystal.h>
String text = "Displayed by Joseph's Terrible C++.";
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print(text);
}
void loop() {
  int len = text.length();
  for (int pos = 0; pos < len; pos++) {
    lcd.scrollDisplayLeft();
    delay(400);
  }
}
```

##### What is going on here?

1. include statement for the "LiquidCrystal" library.
2. make a variable to hold the text to display.
3. connect to the LCD.
5) setup definition
    6) start LCD.
    7) set the LCD cursor position.
    8) print the text to the lcd.
10. loop definition
    11. make a variable with the length of text.
    12. loop through the text
        13. scroll the text left.
        14. wait for 0.4 seconds to keep in time with the LCD's cycles.

#### Python

The Python implementation.

```folder
{
'__main__.py': `
import pyfirmata2 as pyfirmata
from LiquidCrystal import lcd_print, lcd_init

try:
    board = pyfirmata.Arduino(pyfirmata.Arduino.AUTODETECT)
except Exception as e:
    print("Could not connect to board:", e)


text = "Displayed by Joseph's Terrible Python.    "
LCD_LINE_1 = 0x80
LCD_LINE_2 = 0xC0


def getScrolled(text, i):
    o = ""
    for i in range(i, i + 16):
        if i < len(text):
            o += text[i]
        else:
            o += text[i - len(text)]
    return o


def write(text):
    print("\\033[A\\033[A", end="")
    lcd_print(text.split("\\n")[0], LCD_LINE_1)
    print("\\033[44;33m" + text.split("\\n")[0] + "\\033[m")
    try:
        lcd_print(text.split("\\n")[1], LCD_LINE_2)
        print("\\033[44;33m" + text.split("\\n")[1] + "\\033[m")
    except:
        print("\\033[44;33m                \\033[m")


print("\\n")
try:
    lcd_init(
        datapins=[
            False,
            False,
            False,
            False,
            board.get_pin('d:5:o'),
            board.get_pin('d:4:o'),
            board.get_pin('d:3:o'),
            board.get_pin('d:2:o')
        ],
        rs=board.get_pin('d:12:o'),
        e=board.get_pin('d:11:o'),
        LCD_WIDTH=16,
        LCD_CHR=True,
        LCD_CMD=False,
        E_PULSE=0.0005,
        E_DELAY=0.0005
    )
    while True:
        for i in range(len(text)):
            write(getScrolled(text, i))
except KeyboardInterrupt as e:
    print("KeyboardInterrupt")
`,
'LiquidCrystal.py': `
import time


def lcd_init(**kwargs):
    global datapins
    global rs
    global e
    global LCD_WIDTH
    global LCD_CHR
    global LCD_CMD
    global E_PULSE
    global E_DELAY

    datapins = kwargs.get('datapins')
    rs = kwargs.get('rs')
    e = kwargs.get('e')
    LCD_WIDTH = kwargs.get('LCD_WIDTH')
    LCD_CHR = kwargs.get('LCD_CHR')
    LCD_CMD = kwargs.get('LCD_CMD')
    E_PULSE = kwargs.get('E_PULSE')
    E_DELAY = kwargs.get('E_DELAY')

    rs.write(0)
    e.write(0)
    lcd_byte(0x33, LCD_CMD)
    lcd_byte(0x32, LCD_CMD)
    lcd_byte(0x06, LCD_CMD)
    lcd_byte(0x0C, LCD_CMD)
    lcd_byte(0x28, LCD_CMD)
    lcd_byte(0x01, LCD_CMD)
    time.sleep(E_DELAY)


def lcd_byte(bits, mode):
    rs.write(mode)
    datapins[4].write(0)
    datapins[5].write(0)
    datapins[6].write(0)
    datapins[7].write(0)
    if bits & 0x10 == 0x10:
        datapins[4].write(1)
    if bits & 0x20 == 0x20:
        datapins[5].write(1)
    if bits & 0x40 == 0x40:
        datapins[6].write(1)
    if bits & 0x80 == 0x80:
        datapins[7].write(1)
    lcd_toggle_enable()
    datapins[4].write(0)
    datapins[5].write(0)
    datapins[6].write(0)
    datapins[7].write(0)
    if bits & 0x01 == 0x01:
        datapins[4].write(1)
    if bits & 0x02 == 0x02:
        datapins[5].write(1)
    if bits & 0x04 == 0x04:
        datapins[6].write(1)
    if bits & 0x08 == 0x08:
        datapins[7].write(1)
    lcd_toggle_enable()


def lcd_toggle_enable():
    e.write(0)
    time.sleep(E_DELAY)
    e.write(1)
    time.sleep(E_PULSE)
    e.write(0)
    time.sleep(E_DELAY)


def lcd_print(message, line):
    message = message.ljust(LCD_WIDTH, " ")
    lcd_byte(line, LCD_CMD)
    for i in range(LCD_WIDTH):
        lcd_byte(ord(message[i]), LCD_CHR)
`,
}
```

##### What is going on here?

"LiquidCrystal.py" is a simple script I wrote (edited from StackOverflow) to replace LiquidCrystal.h in python.

"\_\_main__.py":

1. import statement for pyfirmata.
2. import statement for LiquidCrystal.py.
4) connect to the Arduino.
10. make a variable to hold the text.
13) a simple function to get a scrolled portion of text.
25. a function to write to the LCD
    26. clear two lines of console.
    27. print the first line to the LCD.
    28. print the first line to the console highlighted in blue.
    29. try/catch in case there isn't a second line (to catch attribute errors).
    30. print the first line to the LCD.
    31. print the first line to the console highlighted in blue.
    33) print a blue line to the console if there is no second line.
36) print 2 lines so that the console doesn't get destroyed by removing lines.
37) try/catch for keyboard interrupts
38) call lcd_init to set up the lcd.
57. loop forever
    58. loop through the text.
        59. print the scrolled text.


### Remote Controlled

In Remote Controlled we will get the LCD to display a simple message and update it with an http server.

#### Firmata

The firmata implementation.

```folder
{
  '__main__.py': `
import pyfirmata2 as pyfirmata
from LiquidCrystal import lcd_print, lcd_init
from httpserver import server
import threading

try:
    board = pyfirmata.Arduino(pyfirmata.Arduino.AUTODETECT)
except Exception as e:
    print("Could not connect to board:", e)


text = "Displayed by Joseph's Terrible Python.    "
LCD_LINE_1 = 0x80
LCD_LINE_2 = 0xC0


def getScrolled(text: str, i):
    o = ""
    text = "{:<17}".format(text)
    for i in range(i, i + 16):
        if i < len(text):
            o += text[i]
        else:
            try:
                o += text[i - len(text)]
            except:
                o += " "
    return o


def write(text):
    print("\\033[A\\033[A", end="")
    lcd_print(text.split("\\n")[0], LCD_LINE_1)
    print("\\033[44;33m" + text.split("\\n")[0] + "\\033[m")
    try:
        lcd_print(text.split("\\n")[1], LCD_LINE_2)
        print("\\033[44;33m" + text.split("\\n")[1] + "\\033[m")
    except:
        print("\\033[44;33m                \\033[m")


print("\\n")
try:
    lcd_init(
        datapins=[
            False,
            False,
            False,
            False,
            board.get_pin('d:5:o'),
            board.get_pin('d:4:o'),
            board.get_pin('d:3:o'),
            board.get_pin('d:2:o')
        ],
        rs=board.get_pin('d:12:o'),
        e=board.get_pin('d:11:o'),
        LCD_WIDTH=16,
        LCD_CHR=True,
        LCD_CMD=False,
        E_PULSE=0.0005,
        E_DELAY=0.0005
    )

    def req(data: str):
        """
        /<TEXT>/
        """
        global text
        d = data.split("/")
        if d[1] == "favicon.ico":
            return
        print(d)
        text = d[1]

    threading.Thread(target=server, args=("127.0.0.1", 1234, req,)).start()
    while True:
        for i in range(len(text)):
            write(getScrolled(text, i))
except KeyboardInterrupt as e:
    print("KeyboardInterrupt")
`,
  'httpserver.py': `
import http.server
from urllib.parse import unquote


def default(*args, **kwargs):
    pass


method = default


class handler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

        method(unquote(self.path))
        self.wfile.write(self.path.encode())


class server:
    def __init__(self, ip, port, handle):
        global method

        self.httpd = http.server.HTTPServer((ip, port), handler)
        method = handle
        self.httpd.serve_forever()
`,
  'LiquidCrystal.py': `
import time


def lcd_init(**kwargs):
    global datapins
    global rs
    global e
    global LCD_WIDTH
    global LCD_CHR
    global LCD_CMD
    global LCD_LINE_1
    global LCD_LINE_2
    global E_PULSE
    global E_DELAY

    datapins = kwargs.get('datapins')
    rs = kwargs.get('rs')
    e = kwargs.get('e')
    LCD_WIDTH = kwargs.get('LCD_WIDTH')
    LCD_CHR = kwargs.get('LCD_CHR')
    LCD_CMD = kwargs.get('LCD_CMD')
    LCD_LINE_1 = kwargs.get('LCD_LINE_1')
    LCD_LINE_2 = kwargs.get('LCD_LINE_2')
    E_PULSE = kwargs.get('E_PULSE')
    E_DELAY = kwargs.get('E_DELAY')

    rs.write(0)
    e.write(0)
    lcd_byte(0x33, LCD_CMD)
    lcd_byte(0x32, LCD_CMD)
    lcd_byte(0x06, LCD_CMD)
    lcd_byte(0x0C, LCD_CMD)
    lcd_byte(0x28, LCD_CMD)
    lcd_byte(0x01, LCD_CMD)
    time.sleep(E_DELAY)


def lcd_byte(bits, mode):
    rs.write(mode)
    datapins[4].write(0)
    datapins[5].write(0)
    datapins[6].write(0)
    datapins[7].write(0)
    if bits & 0x10 == 0x10:
        datapins[4].write(1)
    if bits & 0x20 == 0x20:
        datapins[5].write(1)
    if bits & 0x40 == 0x40:
        datapins[6].write(1)
    if bits & 0x80 == 0x80:
        datapins[7].write(1)
    lcd_toggle_enable()
    datapins[4].write(0)
    datapins[5].write(0)
    datapins[6].write(0)
    datapins[7].write(0)
    if bits & 0x01 == 0x01:
        datapins[4].write(1)
    if bits & 0x02 == 0x02:
        datapins[5].write(1)
    if bits & 0x04 == 0x04:
        datapins[6].write(1)
    if bits & 0x08 == 0x08:
        datapins[7].write(1)
    lcd_toggle_enable()


def lcd_toggle_enable():
    e.write(0)
    time.sleep(E_DELAY)
    e.write(1)
    time.sleep(E_PULSE)
    e.write(0)
    time.sleep(E_DELAY)


def lcd_print(message, line):
    message = message.ljust(LCD_WIDTH, " ")
    lcd_byte(line, LCD_CMD)
    for i in range(LCD_WIDTH):
        lcd_byte(ord(message[i]), LCD_CHR)
`
}
```

##### What is going on here?

"\_\_main__.py":
1. import statement for pyfirmata.
2. import statement for LiquidCrystal.py.
3. import statement for httpserver.py.
4. import statement for threading.
6) connect to the Arduino.
12. make a variable to hold the text.
17) a simple function to get a scrolled portion of text.
31. a function to write to the LCD
    32. clear two lines of console.
    33. print the first line to the LCD.
    34. print the first line to the console highlighted in blue.
    35. try/catch in case there isn't a second line (to catch attribute errors).
    36. print the first line to the LCD.
    37. print the first line to the console highlighted in blue.
    39) print a blue line to the console if there is no second line.
42) print 2 lines so that the console doesn't get destroyed by removing lines.
43) try/catch for keyboard interrupts
44) call lcd_init to set up the lcd.
64. definition for request handler
    65. docstring.
    68) make the text variable global.
    69) split data (path).
    70) handle browser requests to icon.
    72. print d for debug.
    73. update text.
75) start http server in a new thread so it runs asynchronously.
76) loop forever
    77) loop through the text
        78) print the scrolled text.

#### Serial

The serial implementation.

```folder
{
  '__main__.py': `
import serial
import serial.tools.list_ports
from httpserver import server


text = "Displayed by Joseph's Terrible Python and C++.    "

board = serial.Serial(serial.tools.list_ports.comports(True)[
                      0][0], 9600)
board.write(bytes(text, 'UTF-8'))

try:
    def req(data: str):
        """
        /<TEXT>/
        """
        global text
        d = data.split("/")
        if d[1] == "favicon.ico":
            return
        print(d)
        text = d[1]
        board.write(bytes(text, 'UTF-8'))

    server("127.0.0.1", 1234, req,)
except KeyboardInterrupt as e:
    print("KeyboardInterrupt")
    board.close()
`,
  'httpserver.py': `
import http.server
from urllib.parse import unquote


def default(*args, **kwargs):
    pass


method = default


class handler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()

        method(unquote(self.path))
        self.wfile.write(self.path.encode())


class server:
    def __init__(self, ip, port, handle):
        global method

        self.httpd = http.server.HTTPServer((ip, port), handler)
        method = handle
        self.httpd.serve_forever()
`,
'serial.ino': `
#include <LiquidCrystal.h>
String text = "Displayed by Joseph's Terrible C++.";
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() {
  lcd.begin(16, 2);
  lcd.print(text);
  Serial.begin(9600);
}

void loop() {
  int len = text.length();
  for (int pos = 0; pos < len; pos++) {
    if (Serial.available()) {
      text = Serial.readString();
      // text = text.substring(0, text.length() - 1);
      lcd.clear();
      lcd.print(text);
      break;
    }
    lcd.scrollDisplayLeft();
    delay(400);
  }
}

`
}
```

##### What is going on here?

"serial.ino":
1. include statement for the "LiquidCrystal" library.
2. make a variable to hold the text to display.
3. connect to the LCD.
5) setup definition
    6) start LCD.
    7) set the LCD cursor position.
    8) print the text to the lcd.
10. loop definition
    11. make a variable with the length of text.
    12. loop through the text
        14) test if there is serial data waiting to be handled.
        15) if there is serial data set the text variable to the value of the serial data.
        16) remove the trailing newline from text.
        17) clear the LCD.
        18) print to the LCD.
        19) exit from the loop and start again.
        21. scroll the text left.
        22. wait for 0.4 seconds to keep in time with the LCD's cycles.

To test serial.ino on it's own press &lt;kbd&gt;ctrl&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;m&lt;/kbd&gt; or &lt;kbd&gt;command&lt;/kbd&gt; + &lt;kbd&gt;shift&lt;/kbd&gt; + &lt;kbd&gt;m&lt;/kbd&gt; on OSX to open the serial monitor and type in the send box to change the text.

"\_\_main__.py":
1. import statement for serial.
2. import statement for serial.tools.list_ports.
3. import statement for httpserver.py.
6) make a variable to hold the text.
8. connect to the board.
10) write the initial text to the board.
12. try/catch for keyboard interrupts
    13. definition for request handler
        13. docstring.
        17) make the text variable global.
        18) split data (path).
        19) handle browser requests to icon.
        21. print d for debug.
        73. update text.
        74. write the new text to the board.
    25) start http server.

### Digital Clock

In digital clock we will display the current time on the LCD.

```folder
{
  '__main__.py': `
import pyfirmata2 as pyfirmata
from LiquidCrystal import lcd_print, lcd_init
import time

try:
    board = pyfirmata.Arduino(pyfirmata.Arduino.AUTODETECT)
except Exception as e:
    print("Could not connect to board:", e)


LCD_LINE_1 = 0x80
LCD_LINE_2 = 0xC0


def write(text):
    print("\\033[A\\033[A", end="")
    lcd_print(text.split("\\n")[0], LCD_LINE_1)
    print("\\033[44;33m" + text.split("\\n")[0] + "\\033[m")
    try:
        lcd_print(text.split("\\n")[1], LCD_LINE_2)
        print("\\033[44;33m" + text.split("\\n")[1] + "\\033[m")
    except:
        print("\\033[44;33m                \\033[m")


print("\\n")
try:
    lcd_init(
        datapins=[
            False,
            False,
            False,
            False,
            board.get_pin('d:5:o'),
            board.get_pin('d:4:o'),
            board.get_pin('d:3:o'),
            board.get_pin('d:2:o')
        ],
        rs=board.get_pin('d:12:o'),
        e=board.get_pin('d:11:o'),
        LCD_WIDTH=16,
        LCD_CHR=True,
        LCD_CMD=False,
        E_PULSE=0.0005,
        E_DELAY=0.0005
    )

    while True:
        write(time.strftime('%a %d %b %Y ', time.localtime()) +
              '\\n' + time.strftime('%H:%M:%S %Z', time.localtime())[:16])
except KeyboardInterrupt as e:
    print("KeyboardInterrupt")
`,
  'LiquidCrystal.py': `
import time


def lcd_init(**kwargs):
    global datapins
    global rs
    global e
    global LCD_WIDTH
    global LCD_CHR
    global LCD_CMD
    global LCD_LINE_1
    global LCD_LINE_2
    global E_PULSE
    global E_DELAY

    datapins = kwargs.get('datapins')
    rs = kwargs.get('rs')
    e = kwargs.get('e')
    LCD_WIDTH = kwargs.get('LCD_WIDTH')
    LCD_CHR = kwargs.get('LCD_CHR')
    LCD_CMD = kwargs.get('LCD_CMD')
    LCD_LINE_1 = kwargs.get('LCD_LINE_1')
    LCD_LINE_2 = kwargs.get('LCD_LINE_2')
    E_PULSE = kwargs.get('E_PULSE')
    E_DELAY = kwargs.get('E_DELAY')

    rs.write(0)
    e.write(0)
    lcd_byte(0x33, LCD_CMD)
    lcd_byte(0x32, LCD_CMD)
    lcd_byte(0x06, LCD_CMD)
    lcd_byte(0x0C, LCD_CMD)
    lcd_byte(0x28, LCD_CMD)
    lcd_byte(0x01, LCD_CMD)
    time.sleep(E_DELAY)


def lcd_byte(bits, mode):
    rs.write(mode)
    datapins[4].write(0)
    datapins[5].write(0)
    datapins[6].write(0)
    datapins[7].write(0)
    if bits & 0x10 == 0x10:
        datapins[4].write(1)
    if bits & 0x20 == 0x20:
        datapins[5].write(1)
    if bits & 0x40 == 0x40:
        datapins[6].write(1)
    if bits & 0x80 == 0x80:
        datapins[7].write(1)
    lcd_toggle_enable()
    datapins[4].write(0)
    datapins[5].write(0)
    datapins[6].write(0)
    datapins[7].write(0)
    if bits & 0x01 == 0x01:
        datapins[4].write(1)
    if bits & 0x02 == 0x02:
        datapins[5].write(1)
    if bits & 0x04 == 0x04:
        datapins[6].write(1)
    if bits & 0x08 == 0x08:
        datapins[7].write(1)
    lcd_toggle_enable()


def lcd_toggle_enable():
    e.write(0)
    time.sleep(E_DELAY)
    e.write(1)
    time.sleep(E_PULSE)
    e.write(0)
    time.sleep(E_DELAY)


def lcd_print(message, line):
    message = message.ljust(LCD_WIDTH, " ")
    lcd_byte(line, LCD_CMD)
    for i in range(LCD_WIDTH):
        lcd_byte(ord(message[i]), LCD_CHR)
`
}
```

##### What is going on here?

"\_\_main__.py":
1) import statement for pyfirmata.
2) import statement for LiquidCrystal.py.
3) import statement for time.
5. connect to the Arduino.
15) a function to write to the LCD
    16. clear two lines of console.
    17. print the first line to the LCD.
    18. print the first line to the console highlighted in blue.
    19. try/catch in case there isn't a second line (to catch attribute errors).
    20. print the first line to the LCD.
    21. print the first line to the console highlighted in blue.
    23) print a blue line to the console if there is no second line.
26. print 2 lines so that the console doesn't get destroyed by removing lines.
27. try/catch for keyboard interrupts
    28) call lcd_init to set up the lcd.
    48. loop forever
        49) print the formatted time.