几个月前,我购买了一些 WiFi 智能开关,目的是让我的家变得更智能和自动化。几个月过去了,我的家并没有变得更智能,也没有看到自动化,除了我的洗衣机的自动 3 小时程序。直到现在都是这样。

我终于有了一些空闲时间,掸掉了智能开关,并决定要使用它们。一个想法在我脑海中浮现:我可以用这些智能开关在家里设置几个电器,除了可以从任何地方远程操作它们之外,我还可以跟踪每个工作会话的电力消耗和成本它们中的每一个,以及计算特定时间范围(即周、月或年)的总成本和消耗。

在下文中,我将从头到尾描述我如何在 Django 中从头开始制作这个周末项目,并使用 涂鸦物联网平台云 API 将 Django 与我的智能开关。此外,如果您决定要使用它(或者可能改进我创建的应用程序),整个代码将在我的 GitHub 存储库 中提供。

所以让我们开始吧:

1.先决条件

在我们进入项目的编码方面之前,应该完成一些先决条件。这部分有点长,但是为了使项目正常工作,必须正确执行。

首先,您需要注册一个 涂鸦物联网平台 帐户才能访问此项目运行所需的云 API。您可以在此链接上创建一个帐户。

创建帐户并登录平台后,导航到左侧边栏导航上的 Cloud。到达那里后,下一步是创建云项目

要创建云项目,请按同名的蓝色按钮(创建云项目)并在弹出窗口中填写表格。此处重要说明:在表格中提供信息时,请务必在最后一个字段中选择正确的数据中心。例如,如果您位于中欧,则需要在该字段中选择中欧数据中心选项。

在弹出窗口中单击创建后,您应该在下一步中授权 API 服务。基本上,您需要选择项目所需的涂鸦云 API。初始 IoT 核心和授权 API 足以满足此特定项目,但您始终可以更改此设置并在以后向云项目添加更多内容。

好的。现在您已经创建了一个云项目,是时候为它设置适当的设置了。此过程应遵循如下所述:

a) 添加用户

添加用户

在您的云项目中,单击用户选项卡,然后单击添加用户按钮。您可以选择使用该用户的手机号码或电子邮件地址。可以有多个用户,您可以使用与该平台主帐户相同的凭据。请注意,此处此步骤中提供的用户详细信息将用作此云项目的用户,而不是平台本身的用户。

b) 授权用户

授权用户

创建用户后,单击“资产”选项卡,然后单击“授权用户”内部选项卡。接下来,单击添加授权按钮并插入您在上一步中使用的凭据。

c) 添加资产

添加资产

资产是用于指示设备位置的树状拓扑结构。设备属于资产。在实际项目中,每个资产都表示一个实际的物理空间,例如办公楼、农棚或卡车。实际设备属于资产,便于管理。在同一个 Assets 选项卡中,您会在左侧找到 Add Asset 按钮。单击它并插入一个资产名称。

d) 添加设备

添加设备

创建资产后,单击设备内部选项卡(授权用户左侧的选项卡)。接下来,单击添加设备,然后从下拉列表中选择使用 IoT 管理应用程序添加设备(这是一个移动应用程序)。将出现一个带有 QR 码的弹出窗口。您可以在 Play 商店中手动搜索移动应用程序,也可以扫描 QR 码以获取应用程序链接。

物联网管理应用程序是(对于本项目而言)连接您家中的智能开关(和其他智能设备)和通过涂鸦云 API 的 Django 应用程序所必需的应用程序。

安装应用程序后,打开它并在第一个字段中单击方形图标以扫描创建的云项目并将其与应用程序连接。对于帐户和密码,请使用您在步骤 a)(添加用户)中提供的相同凭据。

登录云项目后,您可以单击所有设备,您之前创建的资产应该可见。选择它并单击添加设备操作。之后,您可以手动选择设备(在我的情况下是智能开关),也可以转到“自动扫描”选项卡。请注意,如果您要进行自动扫描(这就是我更喜欢连接我的设备的方式),您的手机需要连接到将用于设备的同一 WiFi,并且您需要重新启动设备/智能切换以出现在屏幕上。

设备出现后,单击下一步,在下一个屏幕上,您将看到您的路由器名称,您需要输入密码,以便设备可以连接到 WiFi。成功完成后,您将在主屏幕上看到添加的设备列表。

通过这一步,完成了云项目和设备连接的设置,现在我们将继续进行下一部分。

2.代码 - 设备

设备

对于这一部分,我会认为你已经对如何设置 Django 项目有基本的了解,所以我不会在这里详细介绍如何做。

话虽如此,让我们继续创建第一个 Django 应用程序:设备。

python manage.py startapp devices

涂鸦云API连接配置

创建“设备”应用程序后,创建一个名为env.py的文件,其中需要包含将此 Django 项目连接到涂鸦云 API 所需的详细信息。为此,请将此代码粘贴到env.py文件中:

ACCESS_ID = "<Insert your Tuya Cloud ACCESS_ID here>"
ACCESS_KEY = "<Insert your Tuya Cloud ACCESS_KEY here>"
API_ENDPOINT = "https://openapi.tuyaeu.com"  # note EU after tuya
MQ_ENDPOINT = "wss://mqe.tuyaeu.com:8285/"  # note EU after tuya

你会在涂鸦物联网平台创建的项目的Overview选项卡的Authorization Key下找到ACCESS_ID和ACCESS_KEY(Access Secret/Client Secret其实就是ACCESS_KEY)。

访问 ID 和访问密钥

对于 API_ENDPOINT 和 MQ_ENDPOINT,请注意tuyaeu.com链接中的 EU。这应该修改为您在创建云项目时选择的数据中心的适当缩写。

设置路由

接下来,在“设备”应用程序文件夹中提供urls.py和以下路由:

from django.urls import path

from . import views

urlpatterns = [
    path('devices/', views.devices, name="devices"),
    path('power/<device_id>', views.power_device, name="power_device"),
    path('monitor/<device_id>', views.monitor_device, name="monitor_device"),
]

不要忘记将“设备”应用程序包含到您的settings.py文件和主项目文件夹的urls.py中。

设置模型

对于“设备”应用程序中的models.py,我使用了以下模型:

from django.conf import settings
from django.db import models
from datetime import datetime
from django.conf.urls.static import static
from django.urls import reverse    


class Device(models.Model):
    name = models.CharField(max_length=150)
    device_id = models.CharField(max_length=150)
    status = models.BooleanField(default=False)
    watts = models.IntegerField(null=True)
    monitoring = models.BooleanField(default=False)
    powered_on = models.DateTimeField(blank=True, null=True)
    powered_off = models.DateTimeField(blank=True, null=True)
    created = models.DateTimeField(auto_now_add=True, blank=True, null=True)

    def __str__(self):
        return self.name

class DeviceLog(models.Model):
    device = models.ForeignKey(Device, on_delete=models.CASCADE, related_name="device")
    powered_on = models.DateTimeField(blank=True, null=True)
    powered_off = models.DateTimeField(blank=True, null=True)
    consumption = models.FloatField(blank=True, null=True)
    cost = models.FloatField(blank=True, null=True)

模型 Device 是存储所有通过 API 调用获取的所需信息的模型,以及项目计算所需的其他字段,这些字段将在views.py中解释

模型 DeviceLog 是存储设备使用会话详细信息的模型。基于此模型中每个设备日志条目的数据,总用电量和成本被汇总并显示在项目的仪表板中。

表格

对于设备视图,只需要一个表单。为了设置表单,在您的“设备”应用程序文件夹中创建forms.py并添加以下表单:

from django.db import models
from .models import *
from django import forms

class setWattsForm(forms.Form):
    watts = forms.IntegerField(widget=forms.NumberInput(attrs={'placeholder': 'Insert device Watts'}))

观点

首先,在“devices”文件夹内的view.py文件的顶部,导入以下包:

from django.shortcuts import render, get_object_or_404, redirect
from datetime import datetime, date
from .models import *
from settings.models import *

基本上,在这里您导入渲染、获取_object_or_404、重定向、日期时间和日期。此视图中即将出现的功能将需要这些包。此外,您可以在此处导入您之前创建的设备应用程序的模型以及将很快创建的设置应用程序中的模型。

连接涂鸦云API

作为此步骤的先决条件,您需要安装一个名为 tuya_connector 的包。为此,在控制台中使用命令

pip install tuya-connector-python

现在,为了在视图中连接涂鸦云 API,首先您将导入日志包。

import logging

接下来,您需要从之前创建的env.py配置文件中导入变量。另外,在安装的 tuya 连接器包中,需要导入 TuyaOpenAPI 和 TUYA_LOGGER。您可以通过以下方式满足这两个要求:

from .env import ACCESS_ID, ACCESS_KEY, API_ENDPOINT
from tuya_connector import TuyaOpenAPI, TUYA_LOGGER

或者,要使用记录器在控制台中调试与 API 的连接,您可以将以下行添加到view.py文件

TUYA_LOGGER.setLevel(logging.DEBUG)

现在,要连接到涂鸦云 API,请插入以下两行:

openapi = TuyaOpenAPI(API_ENDPOINT, ACCESS_ID, ACCESS_KEY)
openapi.connect()

第一行提供连接所需的参数,同时将它们分配给“openapi”变量,第二行进行实际连接。现在,由于您已设置连接,您可以使用“openapi”变量向特定 API 端点发出请求并获取结果。你很快就会在实践中看到这一点。

到目前为止,views.py中的代码应该是这样的:

from django.shortcuts import render, get_object_or_404, redirect
from datetime import datetime, date
from .models import *
from settings.models import *

from .forms import *

# Import Logging
import logging

# Import connection configuration (.env file) & import TuyaOpenAPI and Logger
from .env import ACCESS_ID, ACCESS_KEY, API_ENDPOINT
from tuya_connector import TuyaOpenAPI, TUYA_LOGGER

# Uncomment this if you want to Debug Tuya Cloud Functions
#TUYA_LOGGER.setLevel(logging.DEBUG)

# Connect to TuyaOpenAPI
openapi = TuyaOpenAPI(API_ENDPOINT, ACCESS_ID, ACCESS_KEY)
openapi.connect()

接下来,您需要在views.py文件中包含以下函数:

1.刷新设备功能

# Refresh Devices
def refresh_devices(request):
    # Fetch all available Devices
    all_devices = openapi.get("/v1.2/iot-03/devices")
    all_devices = all_devices['result']['list']

    # Loop through all fetched devices and save/update them in the database
    for device in all_devices:
        device_id = device['id']
        name = device['name']

        # Check the Cloud state of the device
        dev = openapi.get('/v1.0/iot-03/devices/{}/status'.format(device_id))
        state = dev['result'][0]['value']

        obj, created = Device.objects.update_or_create(
            device_id=device_id, defaults={'name': name, 'status':state}

此功能将包含在“设备”功能中,通过该功能,您可能通过物联网设备管理应用程序添加的所有设备都将从 API 端点获取,并在每次重新加载模板时呈现在“设备”模板中,因此您拥有每台设备的最新状态。从请求中获取的信息将存储在数据库中。

从那里,您将能够在此 Django 项目中包含(或排除)任何用于监视的可用设备。

基本上,任何包含的监控设备都将呈现在仪表板模板中,并可用于控制和记录其活动会话。

基本上,此功能通过向“/v1.2/iot-03/devices”端点发出请求并使用此命令将其分配给“all_devices”变量来获取所有可用设备。

all_devices = openapi.get(“/v1.2/iot-03/devices”)

更多关于端点和 IoT Core-Cloud Services API 参考的详细信息,您可以访问以下链接的涂鸦云文档:

涂鸦云文档

2.为设备供电并创建设备日志条目

def power_device(request, device_id):
    today = datetime.now()
    # Get a device
    device = get_object_or_404(Device, device_id=device_id)

    # Check if device is powered on/off
    if device.status:
        commands = {'commands': [{'code': 'switch_1', 'value': False}]}
        device.status = False
        device.save()

        # Update Powered Off time in Device model
        obj, created = Device.objects.update_or_create(
            device_id=device_id, defaults={'powered_off': today}
        )

        # Calculate consumption
        started = device.powered_on
        ended = today

        # difference between the start and the end of an activity in seconds
        dur = ended - started
        duration = dur.total_seconds()

        # convert duration to hours
        hours = duration / 3600

        # calculate device kilowatts
        kilowatts = device.watts / 1000

        # calculate kilowatt-hours
        kwh = hours * kilowatts

        # calculate the activity session cost
        price = Price.objects.last()
        kwh_price = price.kwh_price
        cost = kwh * kwh_price

        # Create DeviceLog entry with each active session of a device
        DeviceLog.objects.create(device_id=device.id, powered_on=device.powered_on, powered_off=today, consumption=kwh, cost=cost)

    else:
        commands = {'commands': [{'code': 'switch_1', 'value': True}]}
        device.status = True
        device.save()

        # Update Powered On time in Device model
        obj, created = Device.objects.update_or_create(
            device_id=device_id, defaults={'powered_on': today}
        )


    # Send the commands for powering on/off
    openapi.post('/v1.0/iot-03/devices/{}/commands'.format(device_id), commands)

    return redirect(request.META['HTTP_REFERER'])

在这个函数中,有两件事同时发生:

第一个是向 'v1.0/iot-03/devices/{}/commands' 端点发送命令(openapi.post(“/v1.0/iot-03/devices/{}/commands”) ) 以打开或关闭特定设备。此操作背后的逻辑是最初在获取所有设备时创建的数据库条目中检查设备的状态状态,以及状态是否为真。这意味着设备已打开,此功能会将设备状态更改为 False,并将发送一个请求,其中包含要关闭设备的命令。

第二件事是这个函数正在为设备的活动会话创建一个设备日志条目。这样,它将计算此设备的活动会话开始和结束之间的持续时间,并在此基础上计算此特定会话的电力消耗和成本。设备日志条目通过 DeviceLog 模型保存到数据库中,并将在仪表板模板的表中可见。

3.设备功能和设置设备的瓦数

def devices(request):
    refresh_devices(request)

    devices = Device.objects.all()

    form = setWattsForm()
    if request.method == 'POST':

        form = setWattsForm(request.POST)

        if form.is_valid():
            device_id = request.POST.get('device_id')
            watts = form.cleaned_data['watts']
            monitoring = True

            Device.objects.filter(device_id=device_id).update_or_create(device_id=device_id, defaults={'watts': watts, 'monitoring': monitoring})


            return redirect('devices')

        else:
            print('Not valid')


    context = {
        'devices': devices,
        'form': form
    }

    return render(request, 'devices.html', context)

此函数将调用“刷新_devices”函数,以获取添加到 IoT 设备管理应用程序中的每个设备的最新信息和状态。此外,它还包含表单背后的逻辑,通过该逻辑,将为选择进行监控的设备设置或更新功率单元或瓦特。功率(瓦特)对于计算千瓦时很重要,因此也是电力消耗成本。

4.设备监控

def monitor_device(request, device_id):
    # Get a device
    device = get_object_or_404(Device, device_id=device_id)

    # Remove device from monitoring state
    if device.monitoring:
        device.monitoring = False
        device.save()

    # Add device for monitoring
    else:
        device.monitoring = True
        device.save()

    return redirect(request.META['HTTP_REFERER'])

这是一个简短的功能,它负责设置设备的监控状态。它将检查设备是否已经在监控,如果是这样,它将为用户提供一个选项以将设备从被监控中删除,并且在相反的情况下——如果设备未被监控,通过此功能它可以添加用于监控并在仪表板模板中可用于操作。

3.代码 - 设置

设置

下一个要创建的 Django 应用是设置。如您所知,执行此操作的命令是:

python manage.py startapp settings

设置将用作您可以设置货币和每千瓦时价格(由您的电力公司设置)的默认值的地方。虽然可能有两种(或更多)不同的用电计费费率,但目前这个项目只是为了简单起见设置一个值。在未来的一些更新中,我将使它支持这个问题的多个值。

设置路由

接下来,在“设置”应用程序文件夹中提供urls.py和以下路由:

from django.urls import path

from . import views

urlpatterns = [
    path('settings/', views.settings, name="settings"),
]

不要忘记将“设置”应用程序包含到您的settings.py文件和主项目文件夹的urls.py中。

设置模型

对于设置应用程序中的models.py,我使用了以下模型:

from django.conf import settings
from django.db import models
from datetime import datetime
from django.urls import reverse    

class Price(models.Model):
    kwh_price = models.FloatField()
    currency_name = models.CharField(max_length=150)
    currency_abbr = models.CharField(max_length=150)
    updated = models.DateTimeField(auto_now_add=True, blank=True, null=True)

    def __str__(self):
        return self.currency_name

模型 Price 存储每千瓦时的价格 (kwh_price)、货币名称 (currency_name)、货币缩写 (currency_abbr),您可以在其中使用特定货币的缩写或符号,以及当这个模型被更新(更新)。请注意,货币缩写或符号会影响模板中定价的呈现,因此长缩写可能会弄乱模板的 CSS。

表格

对于设置视图,只需要一个模型表单。为了设置表单,在您的“设置”应用程序文件夹中创建forms.py并添加以下模型表单:

from django.db import models
from .models import *
from django import forms

class setPriceCurrencyForm(forms.ModelForm):
    kwh_price = forms.FloatField(widget=forms.NumberInput(attrs={'placeholder': 'Insert price'}))
    currency_name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Insert currency name'}))
    currency_abbr = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Insert abbreviation or symbol'}))

    class Meta:
        model = Price
        fields = ("kwh_price", "currency_name", "currency_abbr" )

        def __init__(self, *args, **kwargs):
            super(setPriceCurrencyForm, self).__init__(*args, **kwargs)

观点

首先,在“devices”文件夹内的view.py文件的顶部,导入以下包:

from django.shortcuts import render, get_object_or_404, redirect
from datetime import datetime, date
from devices.models import *
from .models import *
from .forms import *

与之前在“设备”视图中的方式相同,在这里您导入渲染、get_object_or_404、重定向、日期时间和日期。此视图中即将出现的功能将需要这些包。此外,您可以在此处导入您之前创建的设备应用程序的模型以及将很快创建的设置应用程序中的模型。此外,您可以在此处导入在上一步中创建的表单。

接下来,您将需要创建“设置”功能:

def settings(request):

    price = Price.objects.last()

    form = setPriceCurrencyForm(instance=price)
    if request.method == 'POST':

        form = setPriceCurrencyForm(request.POST, instance=price)

        if form.is_valid():
            form.save()

            return redirect('settings')

    context = {
        'form': form,
    }

    return render(request, 'settings.html', context)

这里没有什么复杂的。基本上,此函数设置表单背后的逻辑,用于设置 kWh 价格和货币值。但是,正如您在上面看到的,这些对于“设备”视图中发生的电力消耗成本计算很重要。

4.代码 - 仪表板

仪表板

最后一个要创建的 Django 应用程序是仪表板。

python manage.py startapp dashboard

通过仪表板,您将能够控制添加用于监控的设备,并查看所有受监控设备的设备日志和总用电量成本。在未来的一些更新中,我将通过包含图表来改进仪表板,以使跟踪可视化并使其更美观,并提供更多细节和内容。

设置路由

接下来,在仪表板应用程序文件夹中提供urls.py和以下路由:

from django.urls import path

from . import views

urlpatterns = [
    path('', views.dashboard, name="dashboard"), 
]

设置模型

仪表板应用程序中不需要任何其他模型,因为“仪表板”视图将使用设备和设置应用程序中现有的模型。

观点

首先,在“devices”文件夹中的view.py文件的顶部,导入以下包:

from django.shortcuts import render
from datetime import datetime, date
from devices.models import *
from settings.models import *

from django.db.models import Sum

from devices.views import refresh_devices

与之前在“设备”视图中的方式相同,您可以在此处导入渲染、日期时间和日期。此视图中即将出现的功能将需要这些包。此外,在这里您从 django.db.models 导入 Sum,因为需要它来总结总千瓦时和总成本。

此外,您还需要从 devices.views 中导入 refresh_devices 函数。每次呈现仪表板模板时都需要刷新设备信息和状态。

跟进“仪表板”功能:

def dashboard(request):
    # Check the Cloud state of the devices
    refresh_devices(request)

    # Get all devices
    devices = Device.objects.filter(monitoring=True)

    # Devices count
    devices_count = devices.count()

    # Price per kWh
    price = Price.objects.last()

    # Get the Device Log
    device_log = DeviceLog.objects.all().order_by('-powered_off')

    # Sum total consumption in kWh
    total_kwh = DeviceLog.objects.aggregate(Sum('consumption'))['consumption__sum']

    # Sum total cost
    total_cost = DeviceLog.objects.aggregate(Sum('cost'))['cost__sum']

    context = {
        'devices': devices,
        'device_log': device_log,
        'devices_count': devices_count,
        'price': price,
        'total_kwh': total_kwh,
        'total_cost': total_cost
    }

    return render(request, 'dashboard.html', context)

在这个函数中,所有被监控的设备、被监控设备的总数、每千瓦时的价格和来自 DeviceLog 模型的字段都从数据库中获取并放入上下文中。根据 DeviceLog 列“消耗”和“成本”,计算每列的总和并将其放入上下文中。

最后的话

你设法读到了这一行。你太棒了!感谢您在本文中与我在一起!

这个小项目让我很开心。另外,现在我家的自动化程度更高了;现在我对我的电器有了更多的控制权,这个项目将让我更详细地了解我整个公寓的电费成本。

如果那个时候到了,我希望你能在未来的一些家庭自动化项目中使用这个项目作为基础,并用更多的功能改进它。如果你决定这样做,如果你让我知道,那就太好了。

作为告别的话,不要忘记在我的 Github 存储库中查看整个代码

还有,写完这么多,不给图雅大喊一声就太忘恩负义了。如果没有通过涂鸦物联网平台云和他们组织良好的API 文档连接我的设备的选项,这个项目是不可能的。

嗯......我想就是这样。非常感谢您的到来!


如果您喜欢这篇文章,请考虑订阅我的邮件列表 - 这将是一个很好的支持举措,您以后不会错过任何帖子。此外,您偶尔会收到独家的、仅限订阅者的内容:关于即将到来的项目、折扣、艺术、开发、ui/ux 提示和技巧的幕后信息。没有垃圾邮件,没有 BS。

要订阅,请访问我的 TinyLetter 个人资料。

tinyletter.com/drango

Logo

学AI,认准AI Studio!GPU算力,限时免费领,邀请好友解锁更多惊喜福利 >>>

更多推荐