コード例 #1
0
def setup():
    require(
        "directory", "venv_directory", "www_directory", "package_name",
        "repository", "project_name")

    # 1. clone project
    utils.clone_project()

    # 2. create virtualenv
    utils.create_virtualenv()

    # 3. install requirements
    utils.install_requirements()

    # 4. configure supervisor
    env.supervisor = {
        "command": supervisor.tornado_command()
    }

    supervisor.setup()
    supervisor.reload()

    # 5. configure nginx
    nginx.setup()
    nginx.reload()
コード例 #2
0
    def fetch(self):
        """Fetch data from the url we initialized with, perfom any parsing,
        and display text or graphics. This function does pretty much everything"""
        json_out = None
        image_url = None
        values = []

        gc.collect()
        if self._debug:
            print("Free mem: ", gc.mem_free())  # pylint: disable=no-member

        r = None
        if self._uselocal:
            print("*** USING LOCALFILE FOR DATA - NOT INTERNET!!! ***")
            r = Fake_Requests(LOCALFILE)

        if not r:
            self._connect_esp()
            # great, lets get the data
            print("Retrieving data...", end='')
            self.neo_status((100, 100, 0))   # yellow = fetching data
            gc.collect()
            r = requests.get(self._url)
            gc.collect()
            self.neo_status((0, 0, 100))   # green = got data
            print("Reply is OK!")

        if self._debug:
            print(r.text)

        if self._image_json_path or self._json_path:
            try:
                gc.collect()
                json_out = r.json()
                gc.collect()
            except ValueError:            # failed to parse?
                print("Couldn't parse json: ", r.text)
                raise
            except MemoryError:
                supervisor.reload()

        if self._regexp_path:
            import re

        # extract desired text/values from json
        if self._json_path:
            for path in self._json_path:
                try:
                    values.append(PyPortal._json_traverse(json_out, path))
                except KeyError:
                    print(json_out)
                    raise
        elif self._regexp_path:
            for regexp in self._regexp_path:
                values.append(re.search(regexp, r.text).group(1))
        else:
            values = r.text

        if self._image_json_path:
            try:
                image_url = PyPortal._json_traverse(json_out, self._image_json_path)
            except KeyError as error:
                print("Error finding image data. '" + error.args[0] + "' not found.")
                self.set_background(self._default_bg)

        # we're done with the requests object, lets delete it so we can do more!
        json_out = None
        r = None
        gc.collect()

        if image_url:
            try:
                print("original URL:", image_url)
                image_url = self.image_converter_url(image_url,
                                                     self._image_resize[0],
                                                     self._image_resize[1])
                print("convert URL:", image_url)
                # convert image to bitmap and cache
                #print("**not actually wgetting**")
                filename = "/cache.bmp"
                chunk_size = 12000      # default chunk size is 12K (for QSPI)
                if self._sdcard:
                    filename = "/sd" + filename
                    chunk_size = 512  # current bug in big SD writes -> stick to 1 block
                try:
                    self.wget(image_url, filename, chunk_size=chunk_size)
                except OSError as error:
                    print(error)
                    raise OSError("""\n\nNo writable filesystem found for saving datastream. Insert an SD card or set internal filesystem to be unsafe by setting 'disable_concurrent_write_protection' in the mount options in boot.py""") # pylint: disable=line-too-long
                self.set_background(filename, self._image_position)
            except ValueError as error:
                print("Error displaying cached image. " + error.args[0])
                self.set_background(self._default_bg)
            finally:
                image_url = None
                gc.collect()

        # if we have a callback registered, call it now
        if self._success_callback:
            self._success_callback(values)

        # fill out all the text blocks
        if self._text:
            for i in range(len(self._text)):
                string = None
                if self._text_transform[i]:
                    func = self._text_transform[i]
                    string = func(values[i])
                else:
                    try:
                        string = "{:,d}".format(int(values[i]))
                    except (TypeError, ValueError):
                        string = values[i] # ok its a string
                if self._debug:
                    print("Drawing text", string)
                if self._text_wrap[i]:
                    if self._debug:
                        print("Wrapping text")
                    lines = PyPortal.wrap_nicely(string, self._text_wrap[i])
                    string = '\n'.join(lines)
                self.set_text(string, index=i)
        if len(values) == 1:
            return values[0]
        return values
コード例 #3
0
    def fetch_data(
        self,
        url,
        *,
        headers=None,
        json_path=None,
        regexp_path=None,
        timeout=10,
    ):
        """Fetch data from the specified url and perfom any parsing"""
        json_out = None
        values = []
        content_type = CONTENT_TEXT

        response = self.fetch(url, headers=headers, timeout=timeout)

        headers = {}
        for title, content in response.headers.items():
            headers[title.lower()] = content
        gc.collect()
        if self._debug:
            print("Headers:", headers)
        if response.status_code == 200:
            print("Reply is OK!")
            self.neo_status(STATUS_DATA_RECEIVED)  # green = got data
            if "content-type" in headers:
                if "image/" in headers["content-type"]:
                    content_type = CONTENT_IMAGE
                elif "application/json" in headers["content-type"]:
                    content_type = CONTENT_JSON
                elif "application/javascript" in headers["content-type"]:
                    content_type = CONTENT_JSON
        else:
            if self._debug:
                if "content-length" in headers:
                    print("Content-Length: {}".format(
                        int(headers["content-length"])))
                if "date" in headers:
                    print("Date: {}".format(headers["date"]))
            self.neo_status((100, 0, 0))  # red = http error
            raise HttpError("Code {}: {}".format(
                response.status_code, response.reason.decode("utf-8")))

        if content_type == CONTENT_JSON and json_path is not None:
            if isinstance(
                    json_path,
                (list, tuple)) and (not json_path
                                    or not isinstance(json_path[0],
                                                      (list, tuple))):
                json_path = (json_path, )
            try:
                gc.collect()
                json_out = response.json()
                if self._debug:
                    print(json_out)
                gc.collect()
            except ValueError:  # failed to parse?
                print("Couldn't parse json: ", response.text)
                raise
            except MemoryError:
                supervisor.reload()

        if regexp_path:
            import re  # pylint: disable=import-outside-toplevel

        # optional JSON post processing, apply any transformations
        # these MAY change/add element
        for idx, json_transform in enumerate(self.json_transform):
            try:
                json_transform(json_out)
            except Exception as error:
                print("Exception from json_transform: ", idx, error)
                raise

        # extract desired text/values from json
        if json_out and json_path:
            for path in json_path:
                try:
                    values.append(self.json_traverse(json_out, path))
                except KeyError:
                    print(json_out)
                    raise
        elif content_type == CONTENT_TEXT and regexp_path:
            for regexp in regexp_path:
                values.append(re.search(regexp, response.text).group(1))
        else:
            if json_out:
                # No path given, so return JSON as string for compatibility
                import json  # pylint: disable=import-outside-toplevel

                values = json.dumps(response.json())
            else:
                values = response.text

        # we're done with the requests object, lets delete it so we can do more!
        json_out = None
        response = None
        gc.collect()
        if self._extract_values and len(values) == 1:
            return values[0]

        return values
コード例 #4
0
ファイル: code.py プロジェクト: mikejc58/MatrixClock
 def restart(self, key, val):
     log.message("Restarting MatrixClock")
     time_keeper.clock.chip.square_wave_frequency = 0
     time_keeper.clock.sqw.deinit()
     supervisor.reload()
コード例 #5
0
ファイル: code.py プロジェクト: mikejc58/MatrixClock
                last_sqw = sqw
                display.update()
                
                # Once per second, increment the time
                if not sqw:
                    time_keeper.local_time_secs += 1
                    time_keeper.uptime += 1
    
            # If we processed some long running operation above,
            #   update the running time (local_time_secs) from the clock_chip
            timer.stop
            if timer.diff > 300_000_000:
                # update the time from the clock_chip
                time_keeper.sync_time()
            
        except Exception as e:
            log.message(str(e), add_time=False, traceback=True, exception_value=e)
                
            supervisor.reload()

        time.sleep(0.050)
        
except (KeyboardInterrupt, SystemExit):
    log.message("Exit to REPL")
    try:
        time_keeper.clock.chip.square_wave_frequency = 0
        time_keeper.clock.sqw.deinit()
    except NameError:
        pass

コード例 #6
0
ファイル: sys_main.py プロジェクト: TG-Techie/TG-US
                else:
                    handler.load(sys_config.settings_prog,
                                 sys_config.settings_path)

            handler.cur_cont.current.command(cmd)
            '''if audio_active:
                    if not audio.speaker.playing:
                        audio.speaker.stop()
                        audio.speaker.play_wav('system/audio_files/button_press.wav')'''
            #while audio.speaker.playing:
            #time.sleep(.01)

        #try:handler.unload('example')
        #except: print('dsflkjs')
        '''if audio_active and not audio.speaker.playing:
            audio.speaker.stop()
            time.sleep(.05)
            audio.speaker.play_wav('system/audio_files/looping.wav')'''
        if audio_active:
            while audio.speaker.playing:
                time.sleep(.01)
        del cmd_list

    except MemoryError:
        print('memory error! this is going to be fixed but currently is not')
        try:
            handler.cur_prog._save()
        except:
            pass
        reload()
    #time.sleep(.05)
コード例 #7
0
    def fetch(self):
        json_out = None
        image_url = None
        values = []

        gc.collect()
        if self._debug:
            print("Free mem: ", gc.mem_free())

        r = None
        if self._uselocal:
            print("*** USING LOCALFILE FOR DATA - NOT INTERNET!!! ***")
            r = fake_requests(LOCALFILE)

        if not r:
            self.neo_status((0, 0, 100))
            while not self._esp.is_connected:
                if self._debug:
                    print("Connecting to AP")
                # settings dictionary must contain 'ssid' and 'password' at a minimum
                self.neo_status((100, 0, 0))  # red = not connected
                self._esp.connect(settings)
            # great, lets get the data
            print("Retrieving data...", end='')
            self.neo_status((100, 100, 0))  # yellow = fetching data
            gc.collect()
            r = requests.get(self._url)
            gc.collect()
            self.neo_status((0, 0, 100))  # green = got data
            print("Reply is OK!")

        if self._debug:
            print(r.text)

        if self._image_json_path or self._json_path:
            try:
                gc.collect()
                json_out = r.json()
                gc.collect()
            except ValueError:  # failed to parse?
                print("Couldn't parse json: ", r.text)
                raise
            except MemoryError:
                supervisor.reload()

        if self._xml_path:
            try:
                import xmltok
                print("*" * 40)
                tokens = []
                for i in xmltok.tokenize(r.text):
                    print(i)
                print(tokens)
                print("*" * 40)
            except ValueError:  # failed to parse?
                print("Couldn't parse XML: ", r.text)
                raise

        # extract desired text/values from json
        if self._json_path:
            for path in self._json_path:
                values.append(self._json_pather(json_out, path))
        else:
            values = r.text

        if self._image_json_path:
            image_url = self._json_pather(json_out, self._image_json_path)

        # we're done with the requests object, lets delete it so we can do more!
        json_out = None
        r = None
        gc.collect()

        if image_url:
            print("original URL:", image_url)
            image_url = IMAGE_CONVERTER_SERVICE + image_url
            print("convert URL:", image_url)
            # convert image to bitmap and cache
            #print("**not actually wgetting**")
            self.wget(image_url, "/cache.bmp")
            self.set_background("/cache.bmp")
            image_url = None
            gc.collect()

        # if we have a callback registered, call it now
        if self._success_callback:
            self._success_callback(values)

        # fill out all the text blocks
        if self._text:
            for i in range(len(self._text)):
                string = None
                try:
                    string = "{:,d}".format(int(values[i]))
                except ValueError:
                    string = values[i]  # ok its a string
                if self._debug:
                    print("Drawing text", string)
                if self._text_wrap[i]:
                    if self._debug:
                        print("Wrapping text")
                    string = '\n'.join(
                        self.wrap_nicely(string, self._text_wrap[i]))
                self.set_text(string, index=i)
        if len(values) == 1:
            return values[0]
        return values
コード例 #8
0
ファイル: code.py プロジェクト: HalFrgrd/wirelesskeyboard
 def depress(self):
     supervisor.reload()
コード例 #9
0
def game_over_scene(final_score):
    # Game over scene

    # SOUND
    sound = ugame.audio
    sound.stop()

    # IMAGE_BANK
    over_image_bank = stage.Bank.from_bmp16("splash_over_image_bank.bmp")

    # BACKGROUND
    # sets the background to image 0 in the image Bank
    over_background = stage.Grid(over_image_bank, constants.SCREEN_GRID_X,
                                 constants.SCREEN_GRID_Y)

    # TEXT
    text = []
    text1 = stage.Text(width=29,
                       height=12,
                       font=None,
                       palette=constants.PALETTE,
                       buffer=None)
    text1.move(22, 20)
    text1.text("Final Score: {:0>2d}".format(final_score))
    text.append(text1)

    text2 = stage.Text(width=29,
                       height=14,
                       font=None,
                       palette=constants.PALETTE,
                       buffer=None)
    text2.move(43, 60)
    text2.text("GAME OVER")
    text.append(text2)

    text3 = stage.Text(width=29,
                       height=14,
                       font=None,
                       palette=constants.PALETTE,
                       buffer=None)
    text3.move(35, 110)
    text3.text("PRESS START")
    text.append(text3)

    # STAGE AND RENDER
    # Creates a stage for the background
    # Sets frame rate to 60fps
    game = stage.Stage(ugame.display, constants.FPS)
    # Sets sprite layers and show up in order
    game.layers = text + [over_background]
    # Renders all sprites, only once
    game.render_block()

    while True:
        # get user input
        keys = ugame.buttons.get_pressed()

        # Start button pressed
        if keys & ugame.K_START != 0:
            supervisor.reload()

        # update game logic
        game.tick()
コード例 #10
0
    def fetch(self, refresh_url=None, timeout=10):
        """Fetch data from the url we initialized with, perfom any parsing,
        and display text or graphics. This function does pretty much everything
        Optionally update the URL
        """

        if refresh_url:
            self.url = refresh_url

        response = self.network.fetch(self.url,
                                      headers=self._headers,
                                      timeout=timeout)

        json_out = None
        content_type = self.network.check_response(response)
        json_path = self._json_path

        if content_type == CONTENT_JSON:
            if json_path is not None:
                # Drill down to the json path and set json_out as that node
                if isinstance(
                        json_path,
                    (list, tuple)) and (not json_path or
                                        not isinstance(json_path[0],
                                                       (list, tuple))):
                    json_path = (json_path, )
            try:
                gc.collect()
                json_out = response.json()
                if self._debug:
                    print(json_out)
                gc.collect()
            except ValueError:  # failed to parse?
                print("Couldn't parse json: ", response.text)
                raise
            except MemoryError:
                supervisor.reload()

        try:
            filename, position = self.network.process_image(
                json_out, self.peripherals.sd_check())
            if filename and position is not None:
                self.graphics.set_background(filename, position)
        except ValueError as error:
            print("Error displaying cached image. " + error.args[0])
            if self._default_bg is not None:
                self.graphics.set_background(self._default_bg)
        except KeyError as error:
            print("Error finding image data. '" + error.args[0] +
                  "' not found.")
            self.set_background(self._default_bg)

        if content_type == CONTENT_JSON:
            values = self.network.process_json(json_out, json_path)
        elif content_type == CONTENT_TEXT:
            values = self.network.process_text(response.text,
                                               self._regexp_path)

        # if we have a callback registered, call it now
        if self._success_callback:
            self._success_callback(values)

        self._fill_text_labels(values)
        # Clean up
        json_out = None
        response = None
        gc.collect()

        if len(values) == 1:
            values = values[0]

        return values
コード例 #11
0
    def process(self):
        # Call the debouncing library frequently
        self.joy_z.update()
        self.dpad.update()

        dx = self.x_axis.readJoystickAxis()
        dy = self.y_axis.readJoystickAxis()

        # Command Center State Machine
        #
        if self.state == _UNWIRED:
            self.dotstar_led[0] = ((time.monotonic_ns() >> 23) % 256, 0, 0)
            if dx == 0 and dy == 0:
                self.state = _WAITING
                self.timer = time.monotonic()
        elif self.state == _WAITING:
            self.dotstar_led[0] = ((time.monotonic_ns() >> 23) % 256, 0, 0)
            if dx != 0 or dy != 0:
                self.state = _UNWIRED
            else:
                if time.monotonic() - self.timer > 0.5:
                    self.state = _JOYSTICK
        elif self.state == _JOYSTICK:
            self.dotstar_led[0] = (0, 255, 0)
            if self.joy_z.zPressed():
                self.timer = time.monotonic()
                self.state = _JWAITING
        elif self.state == _JWAITING:
            if not self.joy_z.zPressed():
                self.state = _JOYSTICK
            else:
                if time.monotonic() - self.timer > 1.0:
                    self.mouse.release(Mouse.LEFT_BUTTON)
                    self.mouse.release(Mouse.RIGHT_BUTTON)
                    self.state = _USERCODE
        elif self.state == _USERCODE:
            self.dotstar_led[0] = (0, 0, 0)
            self.dotstar_led.deinit()
            self.joystick_gnd.deinit()
            self.x_axis.deinit()
            self.y_axis.deinit()
            self.dpad.deinit()
            self.joy_z.deinit()
            try:
                # Load usercode.py
                __import__("usercode")
            except ImportError:
                print("Missing usercode.py file")
            # If we get here due to an exception or the user code exiting
            # then restart as it's probably going to by the most stable
            # strategy
            #
            supervisor.reload()

        # Command Center Joystick Handling
        #
        if self.state == _JOYSTICK or self.state == _JWAITING:
            # Determine mouse wheel direction
            #
            dwheel = 0
            if self.dpad.upPressed():
                dwheel = -1
            elif self.dpad.downPressed():
                dwheel = 1

            # Initial quick and dirty mouse movement pacing
            #
            if time.monotonic() - self.last_mouse > 0.005:
                self.last_mouse = time.monotonic()
                self.mouse.move(x=dx, y=dy)

            # Initial quick and dirty mouse scroll wheel pacing
            #
            if time.monotonic() - self.last_mouse_wheel > 0.1:
                self.last_mouse_wheel = time.monotonic()
                self.mouse.move(wheel=dwheel)

            if self.dpad.leftPressedEvent():
                self.mouse.press(Mouse.LEFT_BUTTON)
            elif self.dpad.leftReleasedEvent():
                self.mouse.release(Mouse.LEFT_BUTTON)

            if self.dpad.rightPressedEvent():
                self.mouse.press(Mouse.RIGHT_BUTTON)
            elif self.dpad.rightReleasedEvent():
                self.mouse.release(Mouse.RIGHT_BUTTON)
コード例 #12
0
def driver():
    # Controlling the pixels on the board.
    #pixel_pin = board.NEOPIXEL

    # Controlling the LED strip attached to A1.
    # DEBUG - one of these is wrong, not sure which...
    # A
    #pixel_pin = digitalio.DigitalInOut( board.A0 )
    #pixel_pin.direction = digitalio.Direction.OUTPUT
    # B
    pixel_pin = board.A0
    #
    # DEBUG - when I figure out which it is, use the other to control
    # the circular LED lights.
    circle_pin = board.A1

    # Code for digital switches
    button_1 = digitalio.DigitalInOut(board.A2)
    button_1.direction = digitalio.Direction.INPUT
    button_1.pull = digitalio.Pull.UP

    button_2 = digitalio.DigitalInOut(board.A3)
    button_2.direction = digitalio.Direction.INPUT
    button_2.pull = digitalio.Pull.UP

    button_3 = digitalio.DigitalInOut(board.A4)
    button_3.direction = digitalio.Direction.INPUT
    button_3.pull = digitalio.Pull.UP

    button_4 = digitalio.DigitalInOut(board.A5)
    button_4.direction = digitalio.Direction.INPUT
    button_4.pull = digitalio.Pull.UP

    # Set up our Circle Pixels
    #
    # DEBUG - for the circle pixels we just want them always on doing
    # rainbow stuff.
    num_circle_pixels = 16
    circle_pixels = neopixel.NeoPixel(circle_pin,
                                      num_circle_pixels,
                                      brightness=1.0,
                                      auto_write=False)
    for i in range(len(circle_pixels)):
        circle_pixels[i] = (0, 0, 0)

    circle_path_length = 30
    circle_speed = 11
    circle_trail = 30
    circle_lead = 0

    circle_ps = get_light_ps(circle_path_length, num_circle_pixels)

    # Set up our LED strip
    num_pixels = 28
    pixels = neopixel.NeoPixel(pixel_pin,
                               num_pixels,
                               brightness=1.0,
                               auto_write=False)
    for i in range(len(pixels)):
        pixels[i] = (0, 0, 0)
    zero_pixels = [(0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
                   (0, 0, 0), (0, 0, 0)]

    # Overall model properties for our light.
    path_length = 30
    speed = 24
    trail = 7
    lead = 1.5

    # Light positions for segment 1, and for segment 2, 3, 4.
    #
    # Segments 2, 3, 4 are arranged this way so as to make the
    # animation of the light flow smoothly from segment 1 into the
    # other segments.
    light_ps_1 = [0, 3, 6, 9, 12, 15, 18]
    light_ps_234 = [21, 24, 27, 0, 3, 6, 9]

    # The current time used by the animation model, and the interval
    # in time between updates in the model.
    t = 0
    interval = 3 / 100

    # Establish the initial colors of each of the four ranges to a
    # different spot in the RGB rainbow cycle.
    color_a = 0 * (256 / 4)
    color_b = 1 * (256 / 4)
    color_c = 2 * (256 / 4)
    color_d = 3 * (256 / 4)

    # Loop forever.
    reset_count = 0
    while True:
        # The system locks up after a while - try to hard reboot it around 10 hours in.
        reset_count += 1
        if reset_count > 1000000:
            reset_count = 0
            supervisor.reload()

        # Determine what we need to animate, the rules are:
        # button_1 -> LED segment 1 is
        # button_1 && button_2 -> Segment 2
        # button_1 && button_2 && button_3 -> Segment 3
        # button_1 && button_2 && button_4 -> Segment 4
        # button_1 && button_2 && button_3 && button_4 -> Circle

        # Set up the colors for the light source on each of the four
        # segments.
        peak_a = rainbow(color_a)
        peak_b = rainbow(color_b)
        peak_c = rainbow(color_c)
        peak_d = rainbow(color_d)

        # Update colors for next iteration.
        color_a += 1
        color_a = color_a % 256
        color_b += 1
        color_b = color_b % 256
        color_c += 1
        color_c = color_c % 256
        color_d += 1
        color_d = color_d % 256

        #print( "Buttons: ", [ button_1.value, button_2.value, button_3.value, button_4.value ] )

        button_override = True

        # Light up the appropriate pixels.
        #
        # Switches are active when they read as false.
        tmp = zero_pixels
        if button_override or not button_1.value:
            tmp = animate_path(path_length,
                               speed,
                               trail,
                               lead,
                               light_ps_1,
                               t,
                               peak=peak_a)
        for i in range(len(tmp)):
            pixels[i] = tmp[i]

        tmp = zero_pixels
        if button_override or (not button_1.value and not button_2.value):
            tmp = animate_path(path_length,
                               speed,
                               trail,
                               lead,
                               light_ps_234,
                               t,
                               peak=peak_b)
        for i in range(len(tmp)):
            pixels[7 + i] = tmp[i]

        tmp = zero_pixels
        if button_override or (not button_1.value and not button_2.value
                               and not button_3.value):
            tmp = animate_path(path_length,
                               speed,
                               trail,
                               lead,
                               light_ps_234,
                               t,
                               peak=peak_c)
        for i in range(len(tmp)):
            pixels[14 + i] = tmp[i]

        tmp = zero_pixels
        if button_override or (not button_1.value and not button_2.value
                               and not button_4.value):
            tmp = animate_path(path_length,
                               speed,
                               trail,
                               lead,
                               light_ps_234,
                               t,
                               peak=peak_d)
        for i in range(len(tmp)):
            pixels[21 + i] = tmp[i]

        if button_override or (not button_1.value and not button_2.value
                               and not button_3.value and not button_4.value):
            #circle_tmp = animate_path( circle_path_length, circle_speed, circle_trail, circle_lead, circle_ps, t, peak=peak_a )
            for i in range(len(circle_pixels)):
                circle_pixels[i] = rainbow(255 & int(
                    (i * 256 / num_circle_pixels) + color_a * 10))
        else:
            for i in range(len(circle_pixels)):
                circle_pixels[i] = (0, 0, 0)

        #print( pixels )
        pixels.show()
        circle_pixels.show()
        time.sleep(interval)
        t += interval
        #print( t )
        if t > path_length / speed:
            t -= path_length / speed
コード例 #13
0
def datadog_get_metrics(current_time, query, metric_name, trailing_string,
                        prefix_string, rounding_places, high_threshold):
    '''
    Fetches last data point for a given datadog metric query
    '''
    FROM_TIME = int(current_time) - INTERVAL
    JSON_URL = "https://api.datadoghq.com/api/v1/query?api_key=" + DD_CLIENT_API_KEY + "&application_key=" + DD_CLIENT_APP_KEY + "&from=" + str(
        FROM_TIME) + "&to=" + str(current_time) + "&query=" + query

    print('Using time range in DD request:', FROM_TIME, "to", current_time)
    print('Running query:', query)
    try:
        r = requests.get(JSON_URL)
        print("-" * 60)
        json_resp = r.json()
        # print(json_resp) # Raw JSON
        last_data_point = json_resp["series"][0]["pointlist"][
            -1]  # Get latest value in time series
        print('Last data point:', last_data_point[1])

        # Format results
        # Hack for displaying percentages better
        if "percent_usage" in query:
            print('Formating as percentage')
            formatted_last_data_point = "{:.0%}".format(
                float(last_data_point[1]))
            print(last_data_point[1])
        else:
            if rounding_places < 1:  # Adjust displayed value based on places to round to
                formatted_last_data_point = int(last_data_point[1])
            else:
                formatted_last_data_point = round(last_data_point[1],
                                                  rounding_places)

        # Update display with result
        title_text.text = metric_name
        # Set colour to red if value over threshold
        if last_data_point[1] > high_threshold:
            print('Value over threshold!')
            data_display_label.color = red
        else:
            data_display_label.color = white

        data_display_label.text = prefix_string + str(
            formatted_last_data_point) + trailing_string

        # Process Response headers
        # Check we're not smashing the API rate limit
        if int(r.headers["x-ratelimit-remaining"]) < 500:
            print('Warning! Approaching rate limit. Backing off.')
            print('Rate limit remaining:', r.headers["x-ratelimit-remaining"],
                  'out of', r.headers["x-ratelimit-limit"], 'Period is',
                  r.headers["x-ratelimit-period"])
            time.sleep(RATE_LIMIT_BACKOFF)

        print("-" * 60)
        r.close()
    except Exception as e:
        print(e)
        if "socket failures" in str(
                e
        ):  # TODO: Find out why these intermittent socket failures happen and handle them better. Not sure if its due to flakey wifi, a bug in the Adafruit libs or something else.
            print('Restarting due to socket failures..')
            supervisor.reload()
        else:
            return  # Just return if we dont get a good value from DD
    time.sleep(DELAY_BETWEEN)
    return