title: Raspberry Pi, Socket Error "socket.gaierror: [Errno -3] Temporary failure in name resolution"
body: <p>I have been working on a simple sensor logger for my mini hydroponics setup, using the Google IOT Arm sample code (original code <a href="https://github.com/ARM-software/Cloud-IoT-Core-Kit-Examples/blob/master/CPUTemp/pi_cpu_temp_mqtt.py" rel="nofollow noreferrer">https://github.com/ARM-software/Cloud-IoT-Core-Kit-Examples/blob/master/CPUTemp/pi_cpu_temp_mqtt.py</a>).</p>
  
  <p>It has been working great. Every 60 seconds, the payload delivers sensor data to the Google Cloud, which I track in Data Studio.</p>
  
  <p>I have added Adafruit sensors, and have been happily tracking the sensor data for a few weeks.</p>
  
  <p><strong>The Problem</strong></p>
  
  <p>My router automatically restarts once a day, at 3am, which has caused my Python code to hang. I could simply stop this restart, but instead prefer to catch or avoid the error entirely, in case of more unusual connection issues in future.</p>
  
  <p><strong>The Hope</strong></p>
  
  <p>The ability to reconnect, when able to, and to continue to send data to Google Cloud.</p>
  
  <p>I will be adding control features in future, such as relayed lights and fans, so reliability is crucial to help my plants grow.</p>
  
  <p><strong>The Full Error</strong></p>
  
  <pre><code> Traceback (most recent call last):
    File "lily_telemetry.py", line 220, in &lt;module&gt;
      main()
    File "lily_telemetry.py", line 217, in main
      main()
    File "lily_telemetry.py", line 185, in main
      client.connect(args.mqtt_bridge_hostname, args.mqtt_bridge_port)
    File "/home/pi/.local/lib/python3.5/site-packages/paho/mqtt/client.py", line 839, in connect
      return self.reconnect()
    File "/home/pi/.local/lib/python3.5/site-packages/paho/mqtt/client.py", line 962, in reconnect
      sock = socket.create_connection((self._host, self._port), source_address=(self._bind_address, 0))
    File "/usr/lib/python3.5/socket.py", line 694, in create_connection
      for res in getaddrinfo(host, port, 0, SOCK_STREAM):
    File "/usr/lib/python3.5/socket.py", line 733, in getaddrinfo
      for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
  socket.gaierror: [Errno -3] Temporary failure in name resolution
  </code></pre>
  
  <p><strong>The Code</strong></p>
  
  <pre><code>#!/usr/bin/python
  
  import argparse
  import json
  import datetime
  import time
  import ssl
  import subprocess
  
  import board
  import busio
  import adafruit_mcp9808
  import adafruit_tsl2591
  import digitalio
  
  import jwt
  import paho.mqtt.client as mqtt
  
  # Update and publish temperature readings at a rate of SENSOR_POLL per second.
  SENSOR_POLL=60
  
  # Initialise I2C Master Bus
  i2c_bus = busio.I2C(board.SCL, board.SDA)
  
  # Set temperature sensor inputs MCP9808 board
  mcp1 = adafruit_mcp9808.MCP9808(i2c_bus)
  mcp2 = adafruit_mcp9808.MCP9808(i2c_bus,0x1C)
  
  # Set light sensor inputs TSL2591 board
  tsl = adafruit_tsl2591.TSL2591(i2c_bus)
  
  def create_jwt(project_id, private_key_file, algorithm):
    """Create a JWT (https://jwt.io) to establish an MQTT connection."""
    token = {
        'iat': datetime.datetime.utcnow(),
        'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=60),
        'aud': project_id
    }
    with open(private_key_file, 'r') as f:
      private_key = f.read()
    print('Creating JWT using {} from private key file {}' .format(algorithm, private_key_file))
    return jwt.encode(token, private_key, algorithm=algorithm)
  
  def error_str(rc):
    """Convert a Paho error to a human readable string."""
    return '{}: {}'.format(rc, mqtt.error_string(rc))
  
  class Device(object):
    """Represents the state of a single device."""
    def __init__(self):
      self.temperature = 0
      self.connected = False
  
    def update_sensor_data(self):
      # CPU Temp
      rawdata = subprocess.check_output(["sudo", "/opt/vc/bin/vcgencmd", "measure_temp"]).decode().split('=', 1)[-1].rstrip()
      sendtemp = '"temp":"{}"' .format(rawdata.replace("'", "-").split("-", 1)[0])
      self.temperature = sendtemp
  
      # Temperature Sensor 1 Data
      self.sensortemperature_1 = '"sensor_temp_1":"{}"' .format(mcp1.temperature)
  
      # Temperature Sensor 2 Data
      self.sensortemperature_2 = '"sensor_temp_2":"{}"' .format(mcp2.temperature)
  
      # Light Sensor Data
      lux = tsl.lux
      infrared = tsl.infrared
      visible = tsl.visible
      full_spectrum = tsl.full_spectrum
      self.lightsensor_lux = '"light_sensor_lux":"{}"' .format(round(lux,4))
      self.lightsensor_infrared = '"light_sensor_infrared":"{}"' .format(infrared)
      self.lightsensor_visible = '"light_sensor_visible":"{}"' .format(visible)
      self.lightsensor_full_spectrum = '"light_sensor_full_spectrum":"{}"' .format(full_spectrum)
  
    def wait_for_connection(self, timeout):
      """Wait for the device to become connected."""
      total_time = 0
      while not self.connected and total_time &lt; timeout:
        time.sleep(1)
        total_time += 1
  
      if not self.connected:
        raise RuntimeError('Could not connect to MQTT bridge.')
  
    def on_connect(self, unused_client, unused_userdata, unused_flags, rc):
      """Callback for when a device connects."""
      print('Connection Result:', error_str(rc))
      self.connected = True
  
    def on_disconnect(self, unused_client, unused_userdata, rc):
      """Callback for when a device disconnects."""
      print('Disconnected:', error_str(rc))
      print('...')
      main()
      self.connected = False
  
    def on_publish(self, unused_client, unused_userdata, unused_mid):
      """Callback when the device receives a PUBACK from the MQTT bridge."""
      print('Published message.')
      print("Waiting {} seconds." .format(SENSOR_POLL))
  
    def on_subscribe(self, unused_client, unused_userdata, unused_mid,
                     granted_qos):
      """Callback when the device receives a SUBACK from the MQTT bridge."""
      print('Subscribed: ', granted_qos)
      if granted_qos[0] == 128:
        print('Subscription failed.')
  
  def parse_command_line_args():
    """Parse command line arguments."""
    parser = argparse.ArgumentParser(
        description='Lily Grow Logging using MQTT')
    parser.add_argument(
        '--project_id', required=True, help='GCP cloud project name')
    parser.add_argument(
        '--registry_id', required=True, help='Cloud IoT registry id')
    parser.add_argument('--device_id', required=True, help='Cloud IoT device id')
    parser.add_argument(
        '--private_key_file', required=True, help='Path to private key file.')
    parser.add_argument(
        '--algorithm',
        choices=('RS256', 'ES256'),
        required=True,
        help='Which encryption algorithm to use to generate the JWT.')
    parser.add_argument(
        '--cloud_region', default='us-central1', help='GCP cloud region')
    parser.add_argument(
        '--ca_certs',
        default='roots.pem',
        help='CA root certificate. Get from https://pki.google.com/roots.pem')
    parser.add_argument(
        '--num_messages',
        type=int,
        default=60,
        help='Number of messages to publish.')
    parser.add_argument(
        '--mqtt_bridge_hostname',
        default='mqtt.googleapis.com',
        help='MQTT bridge hostname.')
    parser.add_argument(
        '--mqtt_bridge_port', default=8883, help='MQTT bridge port.')
  
    return parser.parse_args()
  
  def main():
    args = parse_command_line_args()
  
    # Create our MQTT client and connect to Cloud IoT.
    client = mqtt.Client(
        client_id='projects/{}/locations/{}/registries/{}/devices/{}'.format(
            args.project_id, args.cloud_region, args.registry_id, args.device_id))
    client.username_pw_set(
        username='unused',
        password=create_jwt(args.project_id, args.private_key_file,
                            args.algorithm))
    client.tls_set(ca_certs=args.ca_certs, tls_version=ssl.PROTOCOL_TLSv1_2)
  
    device = Device()
  
    client.on_connect = device.on_connect
    client.on_publish = device.on_publish
    client.on_disconnect = device.on_disconnect
    client.on_subscribe = device.on_subscribe
  
    client.connect(args.mqtt_bridge_hostname, args.mqtt_bridge_port)
  
    client.loop_start()
  
    # This is the topic that the device will publish telemetry events (temperature
    # data) to.
    mqtt_telemetry_topic = '/devices/{}/events'.format(args.device_id)
  
    # Wait up to 5 seconds for the device to connect.
    device.wait_for_connection(5)
  
    # Update and publish temperature readings at a rate of SENSOR_POLL per second.
    for _ in range(args.num_messages):
      device.update_sensor_data()
  
    # Time
      sendtime = '"datetime":"{}"'.format(datetime.datetime.now().strftime("%Y-%m-%d"" ""%H:%M:%S.%f"))  
    # Payload
      payload = '{{''{},{},{},{},{},{},{},{}''}}'.format(device.temperature, device.sensortemperature_1,device.sensortemperature_2,device.lightsensor_lux,device.lightsensor_infrared,device.lightsensor_visible,device.lightsensor_full_spectrum,sendtime)
    # Message
      print('Payload: {}'.format(payload))
    # Publish, Sleep
      client.publish(mqtt_telemetry_topic, payload, qos=1)
      time.sleep(SENSOR_POLL)
  
    client.disconnect()
    client.loop_stop()
    print('Finished loop successfully. Goodbye!')
    main()
  
  if __name__ == '__main__':
    main()
  </code></pre>