better Webex
Build, push image, and notify Watchtower / build-image (push) Successful in 42s
Build, push image, and notify Watchtower / notify (push) Successful in 12s

This commit is contained in:
2026-08-17 14:46:35 +02:00
parent 0149c1e5b2
commit 44b4c8034f
3 changed files with 123 additions and 25 deletions
View File
+33 -6
View File
@@ -66,7 +66,7 @@ class WebexManager:
new_doc = self.save_tokens(res.json()) new_doc = self.save_tokens(res.json())
return new_doc["access_token"] return new_doc["access_token"]
def create_support_room(self, client_name: str, client_email: str) -> str: def create_support_room(self, client_name: str, client_email: str, alert_type: str, alert_message: str, alert_id: str) -> str:
"""Creates a team support room and invites the client and yourself.""" """Creates a team support room and invites the client and yourself."""
access_token = self.get_access_token() access_token = self.get_access_token()
headers = { headers = {
@@ -79,12 +79,13 @@ class WebexManager:
f"{self.base_url}/rooms", f"{self.base_url}/rooms",
headers=headers, headers=headers,
json={ json={
"title": f"Smartwave Support: {client_name}", "title": f"Smartwave Support: {client_name} - {alert_type} ({alert_id})",
"teamId": self.team_id "teamId": self.team_id
} }
) )
room_res.raise_for_status() room_res.raise_for_status()
room_id = room_res.json()["id"] room_details = room_res.json()
room_id = room_details["id"]
# 2. Add Client via email (Webex sends invite if user does not exist) # 2. Add Client via email (Webex sends invite if user does not exist)
if client_email: if client_email:
@@ -103,13 +104,39 @@ class WebexManager:
) )
# 4. Optional: Send initial welcome message in the room # 4. Optional: Send initial welcome message in the room
self.send_message(
room_id,
message=f"Support room initialized for {client_name}. An agent will be with you shortly.",
access_token=access_token
)
self.send_alert_info_message(room_id, alert_type, alert_message, alert_id, access_token=access_token)
return room_details
def send_message(self, room_id: str, message: str | None = None, markdown: str | None = None, access_token: str | None = None):
# Fetch the token so it auto-refreshes if needed
if not access_token:
access_token = self.get_access_token()
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
requests.post( requests.post(
f"{self.base_url}/messages", f"{self.base_url}/messages",
headers=headers, headers=headers,
json={ json={
"roomId": room_id, "roomId": room_id,
"text": f"Support room initialized for {client_name}. An agent will be with you shortly." "text": message,
"markdown": markdown
} }
) ).raise_for_status()
return room_id def send_alert_info_message(self, room_id: str, alert_type: str, alert_message: str, alert_id: str, added_alert_info: bool = False, access_token: str | None = None):
"""Sends a structured alert info message to the specified Webex room."""
if added_alert_info:
message = f"Additional Alert Details:\n- Type: {alert_type}\n- Message: {alert_message}\n- Alert ID: {alert_id}"
else:
message = f"Alert Details:\n- Type: {alert_type}\n- Message: {alert_message}\n- Alert ID: {alert_id}"
self.send_message(room_id, message=message, access_token=access_token)
+87 -16
View File
@@ -2,19 +2,17 @@ import os
import asyncio import asyncio
import base64 import base64
import uuid import uuid
import datetime from datetime import datetime, timedelta, timezone
import sys import sys
import json import json
import time from flask import Flask, request, jsonify, current_app
import urllib.parse
import requests
from flask import Flask, request, jsonify, current_app, redirect, url_for
from pymongo import MongoClient from pymongo import MongoClient
from APIs import generate, EdamamAPI from APIs import generate, EdamamAPI
from APIs.mqtt import send_command from APIs.mqtt import send_command
from APIs.webex import WebexManager from APIs.webex import WebexManager
from microwaveCookPlanner import MicrowaveCookPlanner from microwaveCookPlanner import MicrowaveCookPlanner
import safety_checker import safety_checker
import pymongo
sys.path.insert(0, '..') sys.path.insert(0, '..')
try: try:
@@ -177,27 +175,100 @@ async def cooking_params():
@app.route("/alert", methods=["POST"]) @app.route("/alert", methods=["POST"])
def alert(): def alert():
data = request.get_json() or {} data = request.get_json() or {}
alert_collection.insert_one(data)
# Extract client metadata from alert payload (or use fallback values) # 1. Inject a UTC timestamp so we can easily query the 3-minute window
client_name = data.get("client_name", "Unknown Client") data["created_at"] = datetime.now(timezone.utc)
client_email = data.get("client_email") saved_alert = alert_collection.insert_one(data)
room_id = None # Extract orchestrator_id from the incoming alert
orchestrator_id = data.get("orchestrator_id")
# Safely extract alert info (prevents errors if "alert" is missing)
alert_info = data.get("alert", {})
alert_type = alert_info.get("type", "Unknown")
alert_message = alert_info.get("message", "No message provided")
# --- GET CLIENT METADATA ---
client_name = f"Unknown Client (Orchestrator {orchestrator_id})" if orchestrator_id else "Unknown Client"
client_email = None
if orchestrator_id:
client_doc = client_collection.find_one({
"devices": {
"$elemMatch": {
"device_type": "orchestrator",
"device_id": str(orchestrator_id)
}
}
})
if client_doc:
client_name = client_doc.get("client_name", client_name)
client_email = client_doc.get("contact_info", {}).get("email")
# --- WEBEX ROOM LOGIC ---
webex_room_id = None
webex_status = "skipped" webex_status = "skipped"
# Automatically create Webex room if email or client name is supplied # 2. Check if a room was created for this orchestrator in the last 3 minutes
three_minutes_ago = datetime.now(timezone.utc) - timedelta(minutes=3)
recent_alert = alert_collection.find_one({
"orchestrator_id": orchestrator_id,
"webex_room_id": {"$exists": True, "$ne": None},
"created_at": {"$gte": three_minutes_ago},
"_id": {"$ne": saved_alert.inserted_id} # Exclude the alert we just inserted
}, sort=[("created_at", pymongo.DESCENDING)])
if recent_alert:
# A room was created recently -> Reuse it and just send a message
webex_room_id = recent_alert["webex_room_id"]
try: try:
room_id = webex_manager.create_support_room(client_name, client_email) webex_manager.send_alert_info_message(
webex_status = "created" room_id=webex_room_id,
alert_type=alert_type,
alert_message=alert_message,
alert_id=str(saved_alert.inserted_id)
)
webex_status = "reused_room"
except Exception as e:
current_app.logger.exception("Failed to send follow-up message to existing Webex room")
webex_status = f"message_failed: {str(e)}"
else:
# No recent room -> Create a new one
try:
# Assuming your modified create_support_room returns a dict with {"id": ...}
room_details = webex_manager.create_support_room(
client_name,
client_email,
alert_type,
alert_message,
str(saved_alert.inserted_id) # Cast ObjectId to string for JSON serialization
)
# Extract ID based on whether your function returns a dict or just the ID string
webex_room_id = room_details["id"] if isinstance(room_details, dict) else room_details
webex_status = "created_new_room"
except Exception as e: except Exception as e:
current_app.logger.exception("Failed to create Webex support room") current_app.logger.exception("Failed to create Webex support room")
webex_status = f"failed: {str(e)}" webex_status = f"creation_failed: {str(e)}"
# 3. Update the alert document with the Webex Room ID (whether new or reused)
if webex_room_id:
alert_collection.update_one(
{"_id": saved_alert.inserted_id},
{"$set": {"webex_room_id": webex_room_id}}
)
# --- SEND SMS WITH DETAILS ---
# TODO: Add SMS logic here
return jsonify({ return jsonify({
"status": "success", "status": "success",
"message": "Alert saved", "message": "Alert saved",
"webex_room_id": room_id, "webex_room_id": webex_room_id,
"webex_status": webex_status "webex_status": webex_status
}), 200 }), 200
@@ -220,7 +291,7 @@ def telemetry():
return jsonify({"error": "Expected a JSON object/dictionary"}), 400 return jsonify({"error": "Expected a JSON object/dictionary"}), 400
# Stamp UTC timestamp for Node-RED queries # Stamp UTC timestamp for Node-RED queries
data["received_at"] = datetime.datetime.now(datetime.timezone.utc).isoformat() data["received_at"] = datetime.now(datetime.timezone.utc).isoformat()
try: try:
telemetry_collection.insert_one(data) telemetry_collection.insert_one(data)