diff --git a/iotDashboard/device_manager_client.py b/iotDashboard/device_manager_client.py index 4032af1..7d19f62 100644 --- a/iotDashboard/device_manager_client.py +++ b/iotDashboard/device_manager_client.py @@ -10,10 +10,15 @@ from datetime import datetime @dataclass class DeviceRegistrationResponse: device_id: str - certificate_id: str - certificate: str - private_key: str - ca_certificate: str + protocol: str + certificate_id: Optional[str] = None + ca_certificate_pem: Optional[str] = None + certificate_pem: Optional[str] = None + private_key_pem: Optional[str] = None + expires_at: Optional[datetime] = None + credential_id: Optional[str] = None + api_key: Optional[str] = None + webhook_secret: Optional[str] = None @dataclass @@ -21,9 +26,9 @@ class DeviceInfo: id: str name: str location: Optional[str] - is_active: bool + protocol: str + connection_config: Optional[Dict[str, Any]] created_at: datetime - certificates: List[Dict[str, Any]] class DeviceManagerAPIError(Exception): @@ -63,20 +68,33 @@ class DeviceManagerClient: status_code=0, message=f"Connection error: {str(e)}" ) - def register_device(self, name: str, location: Optional[str] = None) -> DeviceRegistrationResponse: - payload = {"name": name} + def register_device( + self, + name: str, + location: Optional[str] = None, + protocol: str = "mqtt", + connection_config: Optional[Dict[str, Any]] = None + ) -> DeviceRegistrationResponse: + payload = {"name": name, "protocol": protocol} if location: payload["location"] = location + if connection_config: + payload["connection_config"] = connection_config response = self._request("POST", "/devices/register", json=payload) data = response.json() return DeviceRegistrationResponse( device_id=data["device_id"], - certificate_id=data["certificate_id"], - certificate=data["certificate"], - private_key=data["private_key"], - ca_certificate=data["ca_certificate"], + protocol=data["protocol"], + certificate_id=data.get("certificate_id"), + ca_certificate_pem=data.get("ca_certificate_pem"), + certificate_pem=data.get("certificate_pem"), + private_key_pem=data.get("private_key_pem"), + expires_at=datetime.fromisoformat(data["expires_at"].replace("Z", "+00:00")) if data.get("expires_at") else None, + credential_id=data.get("credential_id"), + api_key=data.get("api_key"), + webhook_secret=data.get("webhook_secret"), ) def get_device(self, device_id: str) -> DeviceInfo: @@ -87,9 +105,9 @@ class DeviceManagerClient: id=data["id"], name=data["name"], location=data.get("location"), - is_active=data["is_active"], + protocol=data["protocol"], + connection_config=data.get("connection_config"), created_at=datetime.fromisoformat(data["created_at"].replace("Z", "+00:00")), - certificates=data.get("certificates", []), ) def list_devices(self) -> List[DeviceInfo]: @@ -101,11 +119,11 @@ class DeviceManagerClient: id=device["id"], name=device["name"], location=device.get("location"), - is_active=device["is_active"], + protocol=device["protocol"], + connection_config=device.get("connection_config"), created_at=datetime.fromisoformat( device["created_at"].replace("Z", "+00:00") ), - certificates=device.get("certificates", []), ) for device in data ] @@ -114,9 +132,22 @@ class DeviceManagerClient: response = self._request("POST", f"/devices/{device_id}/revoke") return response.json() - def renew_certificate(self, device_id: str) -> Dict[str, Any]: + def renew_certificate(self, device_id: str) -> DeviceRegistrationResponse: response = self._request("POST", f"/devices/{device_id}/renew") - return response.json() + data = response.json() + + return DeviceRegistrationResponse( + device_id=data["device_id"], + protocol=data["protocol"], + certificate_id=data.get("certificate_id"), + ca_certificate_pem=data.get("ca_certificate_pem"), + certificate_pem=data.get("certificate_pem"), + private_key_pem=data.get("private_key_pem"), + expires_at=datetime.fromisoformat(data["expires_at"].replace("Z", "+00:00")) if data.get("expires_at") else None, + credential_id=data.get("credential_id"), + api_key=data.get("api_key"), + webhook_secret=data.get("webhook_secret"), + ) def get_ca_certificate(self) -> str: response = self._request("GET", "/ca_certificate") @@ -137,8 +168,13 @@ class DeviceManagerClient: default_client = DeviceManagerClient() -def register_device(name: str, location: Optional[str] = None) -> DeviceRegistrationResponse: - return default_client.register_device(name, location) +def register_device( + name: str, + location: Optional[str] = None, + protocol: str = "mqtt", + connection_config: Optional[Dict[str, Any]] = None +) -> DeviceRegistrationResponse: + return default_client.register_device(name, location, protocol, connection_config) def get_device(device_id: str) -> DeviceInfo: diff --git a/iotDashboard/forms.py b/iotDashboard/forms.py index a8dc4f6..0a9e1ca 100644 --- a/iotDashboard/forms.py +++ b/iotDashboard/forms.py @@ -1,65 +1,40 @@ +""" +Django forms for the IoT Dashboard. + +Note: Device registration is handled through the device_manager API. +These forms are used for the legacy Django UI only. +""" + from django import forms -from iotDashboard.models import Device, Sensor, SensorType +from iotDashboard.models import Device class DeviceForm(forms.ModelForm): + """ + Form for creating/editing devices. + + Note: This is for the Django UI only. Actual device registration + happens through the device_manager microservice API. + """ + + protocol = forms.ChoiceField( + choices=[ + ("mqtt", "MQTT"), + ("http", "HTTP"), + ("webhook", "Webhook"), + ], + initial="mqtt", + help_text="Communication protocol for this device", + ) + class Meta: model = Device - fields = ["name", "ip", "protocol"] # Exclude sensors from the fields - - def __init__(self, *args, **kwargs): - # No need to handle sensors in the form - super(DeviceForm, self).__init__(*args, **kwargs) - - def save(self, commit=True): - # Save the device instance - device = super(DeviceForm, self).save(commit=False) - - if commit: - device.save() - - return device - - -class SensorWithTypeForm(forms.ModelForm): - # Add fields for SensorType directly in the form - type_name = forms.CharField(max_length=50, label="Sensor Type Name") - unit = forms.CharField(max_length=20, label="Unit", required=False) - protocol = forms.ChoiceField( - choices=[("mqtt", "MQTT"), ("http", "HTTP")], label="Protocol" - ) - topic = forms.CharField(max_length=100, label="Topic", required=False) - endpoint = forms.CharField(max_length=100, label="Endpoint", required=False) - - class Meta: - model = Sensor - fields = ["enabled"] # Exclude 'device' from the form fields - - def __init__(self, *args, **kwargs): - self.device = kwargs.pop("device", None) # Get the device from kwargs - super(SensorWithTypeForm, self).__init__(*args, **kwargs) - - def save(self, commit=True): - # Create or get the SensorType - try: - sensor_type = SensorType.objects.get(name=self.cleaned_data["type_name"]) - except SensorType.DoesNotExist: - sensor_type = SensorType( - name=self.cleaned_data["type_name"], - unit=self.cleaned_data["unit"], - protocol=self.cleaned_data["protocol"], - topic=self.cleaned_data["topic"], - endpoint=self.cleaned_data["endpoint"], - ) - if commit: - sensor_type.save() - - # Create Sensor with the SensorType found or created - sensor = super(SensorWithTypeForm, self).save(commit=False) - sensor.type = sensor_type - sensor.device = self.device # Associate the sensor with the device - - if commit: - sensor.save() - - return sensor + fields = ["name", "location", "protocol"] + widgets = { + "name": forms.TextInput(attrs={"class": "form-control", "placeholder": "Device name"}), + "location": forms.TextInput(attrs={"class": "form-control", "placeholder": "Device location (optional)"}), + } + help_texts = { + "name": "Unique identifier for this device", + "location": "Physical location or description", + } diff --git a/iotDashboard/main.py b/iotDashboard/main.py new file mode 100644 index 0000000..979affc --- /dev/null +++ b/iotDashboard/main.py @@ -0,0 +1,6 @@ +def main(): + print("Hello from iotdashboard!") + + +if __name__ == "__main__": + main() diff --git a/iotDashboard/pyproject.toml b/iotDashboard/pyproject.toml new file mode 100644 index 0000000..7ff8b86 --- /dev/null +++ b/iotDashboard/pyproject.toml @@ -0,0 +1,5 @@ +[project] +name = "dashboard" +version = "0.1.0" +requires-python = ">=3.13" +dependencies = [] diff --git a/iotDashboard/templates/sensor_form.html b/iotDashboard/templates/certificate_renew_confirm.html similarity index 51% rename from iotDashboard/templates/sensor_form.html rename to iotDashboard/templates/certificate_renew_confirm.html index ff1c4db..55d7732 100644 --- a/iotDashboard/templates/sensor_form.html +++ b/iotDashboard/templates/certificate_renew_confirm.html @@ -3,40 +3,39 @@
-