🤖Have you ever tried Chat.M5Stack.com before asking??😎
    M5Stack Community
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Register
    • Login

    UIFlow2 & M5Paper

    SOFTWARE
    2
    2
    92
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • D
      daniel.edge456
      last edited by

      Hi,

      I'm trying to get my m5paper up and running with a basic app to toggle a device.

      The code displays temperature, humidity, co2, IAQ Level all correctly, but the touch interaction with the device is not working - any tips? Also, am I correctly implementing the sleep?

      Thanks so much in advance!

      D

      
      import os, sys, io 
      import M5
      from M5 import *
      import requests2
      import time
      import json
      
      # Global data variable
      data = {}
      data['grow_lamp_state'] = "Unknown"  # To store current state
      
      # Configuration
      ha_url = "xxx"  # Change this to your HA instance
      ha_token = "xxx"
      screenTitle = 'Office Environment'  # Title to display
      wakeup_interval = 300  # 5 minutes in seconds
      
      # Button positioning
      button_x = 270  # Center X position of button
      button_y = 480  # Y position for button (adjust as needed)
      button_width = 200  # Width of button
      button_height = 60  # Height of button
      
      # Define constants for e-ink (black and white)
      WHITE = 0xffffff
      BLACK = 0x000000
      
      def fetchHomeAssistantData(entity_id):
          url = f"{ha_url}/api/states/{entity_id}"
          headers = {
              'Authorization': f'Bearer {ha_token}',
              'Content-Type': 'application/json'
          }
          
          try:
              response = requests2.get(url, headers=headers)
              if response.status_code == 200:
                  return json.loads(response.text)
              else:
                  print(f"Error: {response.status_code}")
                  return None
          except Exception as e:
              print(f"Error fetching data: {e}")
              return None
      
      def toggleGrowLamp():
          url = f"{ha_url}/api/services/light/toggle"
          headers = {
              'Authorization': f'Bearer {ha_token}',
              'Content-Type': 'application/json'
          }
          payload = {
              "entity_id": "light.grow_lamp"
          }
          
          try:
              response = requests2.post(url, headers=headers, data=json.dumps(payload))
              if response.status_code == 200:
                  print("Toggled grow lamp successfully")
                  # Update our stored state (will be refreshed next time)
                  data['grow_lamp_state'] = "on" if data['grow_lamp_state'] == "off" else "off"
                  # Force a re-render
                  render()
                  return True
              else:
                  print(f"Error toggling grow lamp: {response.status_code}")
                  return False
          except Exception as e:
              print(f"Error toggling grow lamp: {e}")
              return False
      
      def aggregateData():
          global data
          # Device data
          try:
              data['batteryPercentage'] = str(M5.Power.getBatteryLevel()) + '%'
              data['voltage'] = f"{M5.Power.getBatVoltage() / 1000:.2f}V"
          except:
              data['batteryPercentage'] = "N/A"
              data['voltage'] = "N/A"
          
          # Check WiFi
          try:
              data['isWifiConnected'] = True  # Assume connected
          except:
              data['isWifiConnected'] = True
          
          data['currentTime'] = time.localtime()
          
          # Fetch Home Assistant data
          try:
              # Temperature from Aranet4
              temp_data = fetchHomeAssistantData("sensor.aranet4_2836d_temperature")
              if temp_data:
                  data['ha_temperature'] = temp_data.get("state", "Unknown")
                  data['ha_temperature_unit'] = temp_data.get("attributes", {}).get("unit_of_measurement", "°C")
              else:
                  data['ha_temperature'] = "Error"
                  data['ha_temperature_unit'] = ""
              
              # Humidity from Aranet4
              humidity_data = fetchHomeAssistantData("sensor.aranet4_2836d_humidity")
              if humidity_data:
                  data['ha_humidity'] = humidity_data.get("state", "Unknown")
                  data['ha_humidity_unit'] = humidity_data.get("attributes", {}).get("unit_of_measurement", "%")
              else:
                  data['ha_humidity'] = "Error"
                  data['ha_humidity_unit'] = ""
              
              # CO2 from Aranet4
              co2_data = fetchHomeAssistantData("sensor.aranet4_2836d_carbon_dioxide")
              if co2_data:
                  data['ha_co2'] = co2_data.get("state", "Unknown")
                  data['ha_co2_unit'] = co2_data.get("attributes", {}).get("unit_of_measurement", "ppm")
              else:
                  data['ha_co2'] = "Error"
                  data['ha_co2_unit'] = ""
              
              # IAQ from office sensor
              iaq_data = fetchHomeAssistantData("sensor.office_iaq_level")
              if iaq_data:
                  data['ha_iaq'] = iaq_data.get("state", "Unknown")
              else:
                  data['ha_iaq'] = "Error"
              
              # Grow lamp state
              lamp_data = fetchHomeAssistantData("light.grow_lamp")
              if lamp_data:
                  data['grow_lamp_state'] = lamp_data.get("state", "Unknown")
              else:
                  data['grow_lamp_state'] = "Unknown"
                  
          except Exception as e:
              print(f"Error in aggregateData: {e}")
      
      def addZero(x):
          if int(x) < 10:
              return '0' + str(x)
          return str(x)
      
      def isButtonPressed(x, y):
          return (x >= button_x - button_width//2 and 
                  x <= button_x + button_width//2 and 
                  y >= button_y - button_height//2 and 
                  y <= button_y + button_height//2)
      
      def render():
          # Clear screen
          M5.Lcd.fillScreen(WHITE)
          M5.Lcd.setTextColor(BLACK, WHITE)
          
          # Header
          M5.Lcd.setTextSize(2)
          M5.Lcd.setCursor(12, 10)
          M5.Lcd.print(screenTitle)
          M5.Lcd.drawLine(0, 40, 540, 40, BLACK)
          
          # Current time in header
          t = data['currentTime']
          time_str = f"{addZero(t[3])}:{addZero(t[4])}"
          date_str = f"{t[0]}-{addZero(t[1])}-{addZero(t[2])}"
          M5.Lcd.setCursor(300, 10)
          M5.Lcd.print(f"{date_str}")
          
          # Main content area
          margin = 20
          y_pos = 80
          
          # Temperature display
          M5.Lcd.setCursor(margin, y_pos)
          M5.Lcd.print("Temperature:")
          
          # Add indicator based on value
          try:
              temp_value = float(data['ha_temperature'])
              indicator = ""
              if temp_value > 25:
                  indicator = "!"  # High
              elif temp_value < 18:
                  indicator = "!"  # Low
              else:
                  indicator = ""   # Good
          except ValueError:
              indicator = "?"
          
          M5.Lcd.setTextSize(3)
          M5.Lcd.setCursor(250, y_pos)
          M5.Lcd.print(f"{data['ha_temperature']}{data['ha_temperature_unit']} {indicator}")
          y_pos += 80
          
          # Reset text size
          M5.Lcd.setTextSize(2)
          
          # Humidity display
          M5.Lcd.setCursor(margin, y_pos)
          M5.Lcd.print("Humidity:")
          
          try:
              humidity_value = float(data['ha_humidity'])
              indicator = ""
              if humidity_value > 60:
                  indicator = "!"  # High
              elif humidity_value < 40:
                  indicator = "!"  # Low
              else:
                  indicator = ""   # Good
          except ValueError:
              indicator = "?"
          
          M5.Lcd.setTextSize(3)
          M5.Lcd.setCursor(250, y_pos)
          M5.Lcd.print(f"{data['ha_humidity']}{data['ha_humidity_unit']} {indicator}")
          y_pos += 80
          
          # Reset text size
          M5.Lcd.setTextSize(2)
          
          # CO2 display
          M5.Lcd.setCursor(margin, y_pos)
          M5.Lcd.print("CO2:")
          
          try:
              co2_value = float(data['ha_co2'])
              indicator = ""
              if co2_value > 1000:
                  indicator = "!"  # Warning
              else:
                  indicator = ""   # Good
          except ValueError:
              indicator = "?"
          
          M5.Lcd.setTextSize(3)
          M5.Lcd.setCursor(250, y_pos)
          M5.Lcd.print(f"{data['ha_co2']} {data['ha_co2_unit']} {indicator}")
          y_pos += 80
          
          # Reset text size
          M5.Lcd.setTextSize(2)
          
          # IAQ display
          M5.Lcd.setCursor(margin, y_pos)
          M5.Lcd.print("IAQ Level:")
          M5.Lcd.setTextSize(3)
          M5.Lcd.setCursor(250, y_pos)
          M5.Lcd.print(f"{data['ha_iaq']}")
          y_pos += 100
          
          # Reset text size
          M5.Lcd.setTextSize(2)
          
          # Divider line
          M5.Lcd.drawLine(margin, y_pos, 540-margin, y_pos, BLACK)
          y_pos += 40
          
          # Grow Lamp Control Button
          global button_y
          button_y = y_pos  # Set the button Y position dynamically
          
          # Draw button
          button_color = BLACK if data['grow_lamp_state'] == "on" else WHITE
          text_color = WHITE if data['grow_lamp_state'] == "on" else BLACK
          
          M5.Lcd.fillRoundRect(
              button_x - button_width//2, 
              button_y - button_height//2, 
              button_width, 
              button_height, 
              10,  # Corner radius
              button_color
          )
          
          # Draw button border
          M5.Lcd.drawRoundRect(
              button_x - button_width//2,
              button_y - button_height//2,
              button_width,
              button_height,
              10,
              BLACK
          )
          
          # Button text
          M5.Lcd.setTextSize(2)
          M5.Lcd.setTextColor(text_color, button_color)
          
          # Calculate centered text position
          text = "Grow Lamp: " + ("ON" if data['grow_lamp_state'] == "on" else "OFF")
          
          # Position for centered text
          text_width = len(text) * 12  # Approximate width based on font size
          text_x = button_x - text_width//2
          text_y = button_y - 10  # Adjust for vertical centering
          
          M5.Lcd.setCursor(text_x, text_y)
          M5.Lcd.print(text)
          
          # Reset text color
          M5.Lcd.setTextColor(BLACK, WHITE)
          
          y_pos += 80  # Add space below button
          
          # Divider line after button
          M5.Lcd.drawLine(margin, y_pos, 540-margin, y_pos, BLACK)
          y_pos += 40
          
          # Device information
          M5.Lcd.setCursor(margin, y_pos)
          M5.Lcd.print("Device Info:")
          y_pos += 40
          
          # Use smaller font for device info
          M5.Lcd.setTextSize(1)
          
          # Battery
          M5.Lcd.setCursor(margin, y_pos)
          M5.Lcd.print(f"Battery: {data['batteryPercentage']}")
          y_pos += 30
          
          # Voltage
          M5.Lcd.setCursor(margin, y_pos)
          M5.Lcd.print(f"Voltage: {data['voltage']}")
          y_pos += 30
          
          # WiFi status
          wifi_status = "Connected" if data['isWifiConnected'] else "Disconnected"
          M5.Lcd.setCursor(margin, y_pos)
          M5.Lcd.print(f"WiFi: {wifi_status}")
          y_pos += 30
          
          # Update interval
          M5.Lcd.setCursor(margin, y_pos)
          M5.Lcd.print(f"Update Interval: {int(wakeup_interval/60)} min")
          y_pos += 30
          
          # Last update time
          t = data['currentTime']
          update_time = f"{addZero(t[3])}:{addZero(t[4])}:{addZero(t[5])}"
          M5.Lcd.setCursor(margin, y_pos)
          M5.Lcd.print(f"Last Updated: {update_time}")
          
          # For e-ink displays
          try:
              M5.update()
          except:
              pass
      
      # Main execution
      try:
          # Initialize
          M5.begin()
          
          # Show loading message
          M5.Lcd.fillScreen(WHITE)
          M5.Lcd.setTextColor(BLACK, WHITE)
          M5.Lcd.setTextSize(2)
          M5.Lcd.setCursor(200, 240)
          M5.Lcd.print("Loading...")
          
          # Try to update display
          try:
              M5.update()
          except:
              pass
          
          # Fetch data and render display
          aggregateData()
          render()
          
          # Keep awake longer to allow interaction
          awake_time = 30  # 30 seconds instead of 10
          awake_start = time.time()
          last_touch_time = 0
          
          # Wait for touch events or timeout
          while time.time() - awake_start < awake_time:
              # Check for touches using native GT911 method
              if hasattr(M5, 'TP'):
                  # For newer firmware with direct touch access
                  if hasattr(M5.TP, 'getStatus') and M5.TP.getStatus():
                      # Get touch point
                      x = M5.TP.getX()
                      y = M5.TP.getY()
                      
                      # Only process touch if it's a new touch (debounce)
                      current_time = time.time()
                      if current_time - last_touch_time > 0.5:
                          if isButtonPressed(x, y):
                              print(f"Button pressed at {x},{y}")
                              toggleGrowLamp()
                              # Reset timeout counter to give more time after interaction
                              awake_start = time.time()
                              last_touch_time = current_time
              
              # Alternative method for M5Paper with different touch API
              try:
                  if hasattr(M5, 'TP') and hasattr(M5.TP, 'touched'):
                      touches = M5.TP.touched()
                      if touches > 0:
                          # Process first touch point
                          point = M5.TP.getPoint(0)
                          x, y = point.x, point.y
                          
                          # Only process touch if it's a new touch (debounce)
                          current_time = time.time()
                          if current_time - last_touch_time > 0.5:
                              if isButtonPressed(x, y):
                                  print(f"Button pressed at {x},{y}")
                                  toggleGrowLamp()
                                  # Reset timeout counter to give more time after interaction
                                  awake_start = time.time()
                                  last_touch_time = current_time
              except:
                  pass
                  
              # Update display if needed
              try:
                  M5.update()
              except:
                  pass
                  
              time.sleep(0.1)
          
          # Try to sleep
          try:
              M5.Power.deepSleep(wakeup_interval * 1000)
          except:
              try:
                  import machine
                  machine.deepsleep(wakeup_interval * 1000)
              except:
                  while True:
                      time.sleep(3600)  # Just sleep in a loop if deep sleep fails
          
      except Exception as e:
          # Display error
          M5.Lcd.fillScreen(WHITE)
          M5.Lcd.setTextColor(BLACK, WHITE)
          M5.Lcd.setTextSize(2)
          M5.Lcd.setCursor(20, 200)
          M5.Lcd.print(f"Error: {str(e)}")
          
          try:
              M5.update()
          except:
              pass
          
          time.sleep(60)
      
      
      
      felmueF 1 Reply Last reply Reply Quote 0
      • felmueF
        felmue @daniel.edge456
        last edited by

        Hello @daniel-edge456

        in UIFlow2 v2.2.6 using touch blocks for M5Paper and then look into the Python tab I get the following code to get touch coordinates:

        if (M5.Touch.getCount()) > 0:
          x = M5.Touch.getX()
          y = M5.Touch.getY()
        

        doing the same with power blocks I get:

        Power.deepSleep(1000, True)
        

        to put M5Paper into deep sleep.

        Thanks
        Felix

        GPIO translation table M5Stack / M5Core2
        Information about various M5Stack products.
        Code examples

        1 Reply Last reply Reply Quote 0
        • First post
          Last post