@@ -776,6 +776,7 @@ CLIENT_ID = os.getenv("CLIENT_ID")
776776CLIENT_SECRET = os.getenv(" CLIENT_SECRET" )
777777THING_ID = os.getenv(" THING_ID" )
778778FLOWRATE_VARIABLE_ID = os.getenv(" FLOWRATE_VARIABLE_ID" )
779+ CLASSIFICATION_VARIABLE_ID = os.getenv(" CLASSIFICATION_VARIABLE_ID" ) # New variable for classification
779780
780781# M4 proxy settings
781782M4_PROXY_HOST = os.getenv(" M4_PROXY_HOST" , " m4proxy" )
@@ -785,45 +786,69 @@ M4_PROXY_PORT = int(os.getenv("M4_PROXY_PORT", "5001"))
785786m4_proxy = Address(M4_PROXY_HOST , M4_PROXY_PORT )
786787
787788def get_sensor_data ():
789+ """
790+ Retrieve the flow rate from the M4 via RPC.
791+ """
788792 client = Client(m4_proxy)
789- return [client.call(" flow_rate" )]
793+ try :
794+ return client.call(" flow_rate" )
795+ except Exception as e:
796+ print (f " Error retrieving sensor data: { e} " )
797+ return None
790798
791- def update_arduino_cloud (value ):
792- url = f " https://api2.arduino.cc/iot/v2/things/ { THING_ID } /properties/ { FLOWRATE_VARIABLE_ID } /publish "
799+ def update_arduino_cloud (variable_id , value ):
800+ """
801+ Send data to Arduino Cloud.
802+ """
803+ url = f " https://api2.arduino.cc/iot/v2/things/ { THING_ID } /properties/ { variable_id} /publish "
793804 headers = {
794805 " Content-Type" : " application/json" ,
795- " Authorization" : f " Bearer { CLIENT_ID } "
806+ " Authorization" : f " Bearer { CLIENT_ID } " # Ensure valid token
796807 }
797808 payload = {" value" : value}
798809
799810 try :
800811 response = requests.put(url, headers = headers, json = payload)
801812 if response.status_code == 200 :
802- print (f " Updated Arduino Cloud: Flow Rate = { value} L/min " )
813+ print (f " Updated Arduino Cloud: { variable_id } = { value} " )
803814 else :
804- print (f " Failed to update Arduino Cloud : { response.status_code} , { response.text} " )
815+ print (f " Failed to update { variable_id } : { response.status_code} , { response.text} " )
805816 except requests.exceptions.RequestException as e:
806817 print (f " Error updating Arduino Cloud: { e} " )
807818
808819def classify_flow (host , port ):
820+ """
821+ Collects flow rate data, sends it for classification, and updates Arduino Cloud.
822+ """
809823 url = f " http:// { host} : { port} /api/features "
810824
811825 while True :
812826 data = {" features" : [], " model_type" : " int8" }
827+
828+ # Collect 100 sensor readings
813829 for _ in range (100 ):
814- data[" features" ].extend(get_sensor_data())
830+ flow_rate = get_sensor_data()
831+
832+ if flow_rate is not None :
833+ data[" features" ].append(flow_rate)
834+ update_arduino_cloud(FLOWRATE_VARIABLE_ID , flow_rate) # Send flow rate to Arduino Cloud
835+
815836 time.sleep(0.1 )
816837
817- response = requests.post(url, json = data)
818- if response.status_code == 200 :
819- classification = response.json().get(" result" , {}).get(" classification" , {})
820- print (f " Classification: { classification} " )
821-
822- if classification:
823- label = max (classification, key = classification.get)
824- update_arduino_cloud(label) # Send classification to Arduino Cloud
825- else :
826- print (f " Failed classification: { response.status_code} " )
838+ # Send collected data for classification
839+ try :
840+ response = requests.post(url, json = data)
841+ if response.status_code == 200 :
842+ classification = response.json().get(" result" , {}).get(" classification" , {})
843+ print (f " Classification: { classification} " )
844+
845+ if classification:
846+ label = max (classification, key = classification.get) # Get highest confidence label
847+ update_arduino_cloud(CLASSIFICATION_VARIABLE_ID , label) # Send classification to Arduino Cloud
848+ else :
849+ print (f " Failed classification: { response.status_code} , { response.text} " )
850+ except requests.exceptions.RequestException as e:
851+ print (f " Error sending classification request: { e} " )
827852
828853if __name__ == " __main__" :
829854 classify_flow(" localhost" , 1337 )
@@ -837,6 +862,7 @@ CLIENT_SECRET=cloud_api_secret
837862THING_ID=cloud_thing_id
838863SPACE_ID=cloud_space_id
839864FLOWRATE_VARIABLE_ID=cloud_flowrate_key
865+ CLASSIFICATION_VARIABLE_ID=cloud_classification_key
840866```
841867
842868The ` docker-compose ` file is updated to include Arduino Cloud credentials:
@@ -862,6 +888,7 @@ services:
862888 CLIENT_SECRET: ${CLIENT_SECRET}
863889 THING_ID: ${THING_ID}
864890 FLOWRATE_VARIABLE_ID: ${FLOWRATE_VARIABLE_ID}
891+ CLASSIFICATION_VARIABLE_ID: ${CLASSIFICATION_VARIABLE_ID}
865892 volumes:
866893 - "/tmp:/tmp"
867894 extra_hosts:
@@ -908,6 +935,8 @@ docker compose logs -f -n 10
908935
909936Once deployed, the system will begin to get flow sensor data, classify it using the trained model and send the results to Arduino Cloud for monitoring and anomaly tracking.
910937
938+ ![ Flow data visualization with Arduino Cloud] ( assets/arduino-cloud-visualization-example.gif )
939+
911940This integration allows real-time anomaly detection and cloud-based monitoring, combining edge inference on Portenta X8 with Arduino Cloud analytics. Users can remotely track flow rate anomalies, set up alerts and analyze historical trends to improve predictive maintenance of the system's point of interest.
912941
913942## Additional Resources
0 commit comments