您现在的位置是:首页 >技术交流 >微信小程序| 基于ChatGPT+明基屏幕挂灯实现超智能家居物联网小程序网站首页技术交流
微信小程序| 基于ChatGPT+明基屏幕挂灯实现超智能家居物联网小程序
一、需求背景
在尝试了这么多次的ChatGPT
在纯软方向的应用开发后,深感LLM(大语言模型)
的能力之强大。俗话说得好:心有多大舞台就有多大!
基于AI大模型,可以尝试的方面实在是数不胜数!轻轻松松就可以突破在移动互联网时代APP/平台所积累下的数据壁垒和优势!以及像一些高门槛且需要大量的人力和物力才能实现的功能,现在借助现成的AI大模型能力可以以更低的成本实现!
所以,这次我们来做点不一样的!这一期来尝试一下ChatGPT
与物联网(IoT)
结合的项目!
说到物联网(IoT--【Internet of Thing】)
大家可能会有许些的陌生,那么直白来说就是万物互联
–也就是近几年很火的智能家居,在通信硬件的能力的支持下,按照统一的通信协议来共享并分析各个设备所采集数据,从而实现系统更加贴近人的使用习惯!真正做到家具智能化!
那么问题来了,作为一个程序打工人天天接触最多的电器无非就是笔记本和显示器!
这两样作为职业生涯中的吃饭家伙!这不得好好地伺候一手,这完全可以借助ChatGPT的能力
把他们进行智能化改造!
那么从哪里入手呢?
- 对于笔记本: 作为生产力的来源,其本身就是一个多方面的输入输出设备,说到底要让其变得更加智能,我想应该没有比给他加一张
4070显卡
或者加两条64G内存条
来的更快、更直接、更有效果吧!【目前暂时没有想到可以借助ChatGPT能力
的方向,如果大家有好的主意,欢迎随时扣我!】 - 对于显示器: 这是一个纯粹的输出设备,它无偿接收来之外界的全部信号!只要能吃得下,照单全收!俗话说得好:成绩越差潜力越大! 所以,我们这一期的主角诞生了,我们这一次就借助
ChatGPT
的能力硬将其从呆板的输出源能力扩充为智能小助手!
那么问题又来了!
作为一个死板的显示器,只有一个显示屏,几个物理按键,没有任何的智能化的组件,又要如何植入ChatGPT的能力
呢?
那么这个时候我们需要借助一些外在的智能物理设备,来赋能显示器实现智能化!所以很显然,说到显示器====我想第一时间想到的大概率是电脑台灯
!
需求也很明确:我们需要一台带有智能控制和通信于一体的护眼台灯
于是乎,什么话都不用多说,打开淘宝走起。搜索"智能电脑台灯"
。相信群众的眼睛是雪亮的,整一手“按销量排序”。直接无脑相信销量第一的智能王者!----明基智能屏幕挂灯(ScreenBar Halo)
那么问题又又又来了!
- 这玩意真的有这么智能嘛?它真的经接得住我们的
ChatGPT
的智能大改造嘛? - 你说这玩意这么好,这不就是个灯嘛?整个能亮的不就行?
- 首先智能不智能我们需要第一步先看硬件,要将其与
ChatGPT
打通,智能的无线通信调节功能必不可少!
从该台灯的详细介绍中,轻而易举我们可以获得答案:
功能特性 | |
---|---|
- 其次,第二个方面,我们选择台灯只是难道仅仅是因为其能发光发亮嘛?仅仅是为了满足在黑夜中寻找到漆黑的左手??,醒醒把兄弟,都是为了护眼吧!所以都是为了对眼睛好,我们寻找到一台护眼功能给力的利器,这难道不是成功的第一步?!
从两款台灯的功能对比中,轻而易举我们可以获得答案:
网红爆款将就型 | 高科技智能型 |
---|---|
为了实现智能家居小程序
,以及消除大家的疑虑,我直接将两个灯买回来进行对比使用,以下是一些不同角度的对比例证,哪个适合我们的项目高下立见:
- 首先先从宣传照跟实际使用来感受一波区别对比:
宣传效果图 | 实际使用效果图 |
---|---|
对于传统的台灯来说,亮度稍微一调大,便直接在屏幕上留下了一道白斑! 灯光效果实在是一言难尽!
不仅如此,·后部亮灯模式又给灯具添加了几分高级色彩!氛围拉满!·
说到重中之重,论灯具的智能性,`一个有无线长距离控制器,一个是有限束缚控制器!
智能性高下立见!
控制器对比 | 智能无线控制器使用展示 |
---|---|
二、项目原理及架构
2.1 实现原理
ChatGPT Prompt提示词
设置
你是一位智能家居助手,
现在开始你需要根据我的作息时间从健康护眼的角度触发对我的台灯参数进行设置,
同时将灯的亮度和色温推荐给我。
输入示例:
{
起床:9:00,
早晨阅读:9:30--10:10,
程序开发:10:30--12:00,
午休:12:00--14:00,
程序开发:14:10--18:30,
看电影休闲:19:00--21:00,
晚间阅读:22:00--23:00
}
指令输出:
{
护眼模式:9:30--10:10,
均衡模式:10:30--12:00,
氛围模式:12:00--14:00,
冷光模式:14:10--18:30,
喜好模式:19:00--21:00,
暖光模式:22:00--23:00
}
实际输入:
{
起床:10:00,
程序开发:10:30--12:00,
午休:12:00--14:00,
打游戏:14:10--18:30,
看电影休闲:19:00--21:00,
晚间游戏:22:00--23:00
}
指令输出:
把
ChatGPT
设置为智能家居小助手,并将构建好的Prompt
结合自身的作息规律然后输入到ChatGPT
中,从而得出ChatGPT小助手
所推荐的台灯护眼方案。
ChatGPT家居小助手
护眼方案输出:
根据您提供的作息时间,我会为您设置台灯的参数,以健康护眼为出发点。以下是对应的台灯模式设置和推荐的亮度和色温:
护眼模式:10:30--12:00,这个时间段您在进行程序开发,护眼模式会提供柔和的光线,推荐亮度为50%、色温为4000K。
均衡模式:12:00--14:00,这个时间段是您的午休时间,均衡模式会提供适中的光线,推荐亮度为60%、色温为4500K。
氛围模式:14:10--18:30,这个时间段您会打游戏,氛围模式会提供舒适的光线,推荐亮度为70%、色温为5000K。
冷光模式:19:00--21:00,这个时间段您会看电影休闲,冷光模式会提供明亮而清晰的光线,推荐亮度为80%、色温为5500K。
喜好模式:22:00--23:00,这个时间段您会进行晚间游戏,喜好模式可以根据您的个人喜好设置台灯的参数,您可以根据需要调整亮度和色温。
暖光模式:根据您提供的作息时间,没有明确的晚间阅读时间段,所以我会将晚间阅读时间段设置为暖光模式,时间为22:00--23:00,这样可以给您提供柔和而温暖的光线,推荐亮度为60%、色温为3500K。
这些设置将根据您的作息时间自动调整台灯的亮度和色温,以最大程度地保护您的眼睛健康。请注意,以上是根据一般的护眼建议进行的设置和推荐,您可以根据个人喜好和舒适度对亮度和色温进行微调。如有其他需求或疑问,请随时告诉我。
2.2 技术架构
2.3 技术栈
模块 | 语言及框架 | 涉及的技术要点 |
---|---|---|
小程序前端 | 基于VUE 2.0语法 +Uni-app跨平台开发框架 | Http接口通信、Flex布局方式、uView样式库的使用、JSON数据解析、定时器的使用 |
小程序接口服务端 | Python + Flask WEB框架 | rest接口的开发、 ChatGPT API接口的数据对接 、 前后端websocket实时通信 |
影刀RPA手机自动化 | Python + 安卓手机USB调试 | 安卓手机的USB调试功能的开启与调试,APP元素的定位以及操作app元素的python脚本编写 |
2.4 数据交互原理
三、项目功能的实现
3.1 ChatGPT API的接入
要接入ChatGPT API,需要按照以下步骤进行操作:
- 注册一个账号并登录到OpenAI的官网:https://openai.com/
- 在Dashboard页面上,创建一个API密钥。在“API Keys”选项卡下,点击“Generate New Key”按钮。将生成的密钥保存好,以备后续使用。
- 选择所需的API服务,例如“Completion” API,以使用OpenAI的文本生成功能。
使用Python
调用ChatGPT API
实现代码如下:
- 方法一:使用
request
库
import requests
import json
# 构建API请求
url = "https://api.openai.com/v1/engines/davinci-codex/completions"
headers = {"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_KEY"}
data = {
"prompt": "Hello, my name is",
"max_tokens": 5
}
# 发送API请求
response = requests.post(url, headers=headers, data=json.dumps(data))
# 解析API响应
response_data = json.loads(response.text)
generated_text = response_data["choices"][0]["text"]
print(generated_text)
- 方式二:使用
openAI库
from flask import Flask, request
import openai
app = Flask(__name__)
openai.api_key = "YOUR_API_KEY_HERE"
@app.route("/")
def home():
return "Hello, World!"
@app.route("/chat", methods=["POST"])
def chat():
data = request.json
response = openai.Completion.create(
engine="davinci",
prompt=data["message"],
max_tokens=60
)
return response.choices[0].text
if __name__ == "__main__":
app.run()
3.2 小程序端设计与实现
台灯控制首页 | 圆盘亮度调节 |
---|---|
首页控制元素详细源码如下:
<template>
<view class="template-outset">
<!-- 流星-->
<view class="tn-satr">
<view class="sky"></view>
<view class="stars">
<view class="falling-stars">
<view class="star-fall"></view>
<view class="star-fall"></view>
<view class="star-fall"></view>
<view class="star-fall"></view>
</view>
<view class="small-stars">
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
</view>
<view class="medium-stars">
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
<view class="star"></view>
</view>
</view>
</view>
<view class="tn-text-center tn-color-gray--disabled" style="padding: 5vh 0 0 0; position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
z-index: 9999999;
width: 56vh;
height: 50vh;">
<view class="tn-flex tn-flex-wrap">
<view class="tn-flex-basic-md">
<view class="tn-padding-lg tn-margin-xs tn-radius bg-flex-shadow tn-shadow-blur">
<zai-lattice shadow progressColor='#fff93a' :progressPercent="Number(40)" title='亮度'
:num='lightNum' unit='%' @click="fixFlag = 1" />
</view>
</view>
<view class="tn-flex-basic-md">
<view class="tn-padding-lg tn-margin-xs tn-radius bg-flex-shadow tn-shadow-blur">
<zai-lattice shadow progressColor='#1af4ff' :progressPercent="Number(40)" title='色温'
:num='tempretureNum' unit='%' @click="fixFlag = 2" />
</view>
</view>
</view>
<light-condition @change="changeNumber" style="margin-bottom: 40px;"></light-condition>
<view class='nav-list'>
<block v-for="(content_item, content_index) in titles" :key="content_index">
<navigator open-type="navigate" hover-class='none' :url="content_item.url"
class="nav-list-item tn-shadow-blur tn-cool-bg-image tn-flex tn-flex-col-center tn-flex-row-between"
:class="[
getRandomCoolBg(content_index)
]">
<view class="nav-link tn-flex-1">
<view class='title'>{{ content_item.title }}</view>
</view>
<view class="icon">
<view :class="['tn-icon-' + content_item.icon]"></view>
</view>
</navigator>
</block>
</view>
</view>
<view class="tnwave waveAnimation">
<view class="waveWrapperInner bgTop">
<view class="wave waveTop"
style="background-image: url('https://tnuiimage.tnkjapp.com/wave/wave-2.png')"></view>
</view>
<view class="waveWrapperInner bgMiddle">
<view class="wave waveMiddle"
style="background-image: url('https://tnuiimage.tnkjapp.com/wave/wave-2.png')"></view>
</view>
<view class="waveWrapperInner bgBottom">
<view class="wave waveBottom"
style="background-image: url('https://tnuiimage.tnkjapp.com/wave/wave-1.png')"></view>
</view>
</view>
<!-- <nav-index-button style="position: fixed;z-index: 999999;" @click.native="navToUrl()"></nav-index-button> -->
</view>
</template>
<script>
import zaiLattice from "../../components/zai-lattice";
import lightCondition from "@/components/comid-Ucharts/bar.vue"
import template_page_mixin from './template_page_mixin.js'
import NavIndexButton from './nav-index-button.vue'
export default {
name: 'TemplateWave',
mixins: [template_page_mixin],
components: {
NavIndexButton,
zaiLattice,
lightCondition
},
data() {
return {
fixFlag: 1,
lightNum: 0,
tempretureNum: 0,
titles: [{
title: 'AI调节',
icon: 'trophy-fill'
},
{
title: '行为分析',
icon: 'inventory-fill',
url:"./report"
}
]
}
},
methods: {
getRandomCoolBg() {
return this.$tn.color.getRandomCoolBgClass()
},
navToUrl() {
console.log("===-----99")
},
changeNumber(e) {
console.log('==c==', e)
if (this.fixFlag === 1) {
this.lightNum = e
}
if (this.fixFlag === 2) {
this.tempretureNum = e
}
}
}
}
</script>
<style lang="scss" scoped>
@import './custom_nav_bar.scss';
@import '@/tuniao-ui/libs/css/main.scss';
@keyframes suspension {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-0.8rem);
}
}
/* 用户信息 start */
.user-info {
&__container {
position: absolute;
top: 25vh;
left: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
&__avatar {
width: 200rpx;
height: 200rpx;
border: 8rpx solid rgba(255, 255, 255, 0.05);
border-radius: 50%;
overflow: hidden;
box-shadow: 0rpx 0rpx 80rpx 0rpx rgba(0, 0, 0, 0.15);
}
&__nick-name {
color: #FFFFFF;
margin-top: 26rpx;
font-size: 36rpx;
font-weight: 600;
text-align: center;
}
}
/* 用户信息 end */
/* 流星*/
.tn-satr {
position: fixed;
width: 100%;
height: 600px;
overflow: hidden;
flex-shrink: 0;
z-index: 998;
}
.stars {
position: absolute;
z-index: 1;
width: 100%;
height: 100px;
}
.star {
border-radius: 50%;
background: #ffffff;
box-shadow: 0px 0px 6px 0px rgba(255, 255, 255, 0.8);
}
.small-stars .star {
position: absolute;
width: 3px;
height: 3px;
}
.small-stars .star:nth-child(2n) {
opacity: 0;
-webkit-animation: star-blink 1.2s linear infinite alternate;
animation: star-blink 1.2s linear infinite alternate;
}
.small-stars .star:nth-child(1) {
left: 40px;
bottom: 50px;
}
.small-stars .star:nth-child(2) {
left: 200px;
bottom: 40px;
}
.small-stars .star:nth-child(3) {
left: 60px;
bottom: 120px;
}
.small-stars .star:nth-child(4) {
left: 140px;
bottom: 250px;
}
.small-stars .star:nth-child(5) {
left: 400px;
bottom: 300px;
}
.small-stars .star:nth-child(6) {
left: 170px;
bottom: 80px;
}
.small-stars .star:nth-child(7) {
left: 200px;
bottom: 360px;
-webkit-animation-delay: .2s;
animation-delay: .2s;
}
.small-stars .star:nth-child(8) {
left: 250px;
bottom: 320px;
}
.small-stars .star:nth-child(9) {
left: 300px;
bottom: 340px;
}
.small-stars .star:nth-child(10) {
left: 130px;
bottom: 320px;
-webkit-animation-delay: .5s;
animation-delay: .5s;
}
.small-stars .star:nth-child(11) {
left: 230px;
bottom: 330px;
-webkit-animation-delay: 7s;
animation-delay: 7s;
}
.small-stars .star:nth-child(12) {
left: 300px;
bottom: 360px;
-webkit-animation-delay: .3s;
animation-delay: .3s;
}
@-webkit-keyframes star-blink {
50% {
width: 3px;
height: 3px;
opacity: 1;
}
}
@keyframes star-blink {
50% {
width: 3px;
height: 3px;
opacity: 1;
}
}
.medium-stars .star {
position: absolute;
width: 3px;
height: 3px;
opacity: 0;
-webkit-animation: star-blink 1.2s ease-in infinite alternate;
animation: star-blink 1.2s ease-in infinite alternate;
}
.medium-stars .star:nth-child(1) {
left: 300px;
bottom: 50px;
}
.medium-stars .star:nth-child(2) {
left: 400px;
bottom: 40px;
-webkit-animation-delay: .4s;
animation-delay: .4s;
}
.medium-stars .star:nth-child(3) {
left: 330px;
bottom: 300px;
-webkit-animation-delay: .2s;
animation-delay: .2s;
}
.medium-stars .star:nth-child(4) {
left: 460px;
bottom: 300px;
-webkit-animation-delay: .9s;
animation-delay: .9s;
}
.medium-stars .star:nth-child(5) {
left: 300px;
bottom: 150px;
-webkit-animation-delay: 1.2s;
animation-delay: 1.2s;
}
.medium-stars .star:nth-child(6) {
left: 440px;
bottom: 120px;
-webkit-animation-delay: 1s;
animation-delay: 1s;
}
.medium-stars .star:nth-child(7) {
left: 200px;
bottom: 140px;
-webkit-animation-delay: .8s;
animation-delay: .8s;
}
.medium-stars .star:nth-child(8) {
left: 30px;
bottom: 480px;
-webkit-animation-delay: .3s;
animation-delay: .3s;
}
.medium-stars .star:nth-child(9) {
left: 460px;
bottom: 400px;
-webkit-animation-delay: 1.2s;
animation-delay: 1.2s;
}
.medium-stars .star:nth-child(10) {
left: 150px;
bottom: 10px;
-webkit-animation-delay: 1s;
animation-delay: 1s;
}
.medium-stars .star:nth-child(11) {
left: 420px;
bottom: 450px;
-webkit-animation-delay: 1.2s;
animation-delay: 1.2s;
}
.medium-stars .star:nth-child(12) {
left: 340px;
bottom: 180px;
-webkit-animation-delay: 1.1s;
animation-delay: 1.1s;
}
@keyframes star-blink {
50% {
width: 4px;
height: 4px;
opacity: 1;
}
}
.star-fall {
position: relative;
border-radius: 2px;
width: 80px;
height: 2px;
overflow: hidden;
-webkit-transform: rotate(-20deg);
transform: rotate(-20deg);
}
.star-fall:after {
content: "";
position: absolute;
width: 50px;
height: 2px;
background: -webkit-gradient(linear, right top, left top, from(rgba(0, 0, 0, 0)), to(rgba(255, 255, 255, 0.4)));
background: linear-gradient(to left, rgba(0, 0, 0, 0) 0%, rgba(255, 255, 255, 0.4) 100%);
left: 100%;
-webkit-animation: star-fall 3.6s linear infinite;
animation: star-fall 3.6s linear infinite;
}
.star-fall:nth-child(1) {
left: 80px;
bottom: -100px;
}
.star-fall:nth-child(1):after {
-webkit-animation-delay: 2.4s;
animation-delay: 2.4s;
}
.star-fall:nth-child(2) {
left: 200px;
bottom: -200px;
}
.star-fall:nth-child(2):after {
-webkit-animation-delay: 2s;
animation-delay: 2s;
}
.star-fall:nth-child(3) {
left: 430px;
bottom: -50px;
}
.star-fall:nth-child(3):after {
-webkit-animation-delay: 3.6s;
animation-delay: 3.6s;
}
.star-fall:nth-child(4) {
left: 400px;
bottom: 100px;
}
.star-fall:nth-child(4):after {
-webkit-animation-delay: .2s;
animation-delay: .2s;
}
@-webkit-keyframes star-fall {
20% {
left: -100%;
}
100% {
left: -100%;
}
}
@keyframes star-fall {
20% {
left: -100%;
}
100% {
left: -100%;
}
}
/* 波浪*/
.template-outset {
background-image: linear-gradient(to top, #4C3FAE 20%, #6E26BA 80%);
width: 100vw;
height: 100vh;
}
@keyframes move_wave {
0% {
transform: translateX(0) translateZ(0) scaleY(1)
}
50% {
transform: translateX(-25%) translateZ(0) scaleY(1)
}
100% {
transform: translateX(-50%) translateZ(0) scaleY(1)
}
}
.tnwave {
overflow: hidden;
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
margin: auto;
}
.waveWrapperInner {
position: absolute;
width: 100%;
overflow: hidden;
height: 100%;
}
.wave {
position: absolute;
left: 0;
width: 200%;
height: 100%;
background-repeat: repeat no-repeat;
background-position: 0 bottom;
transform-origin: center bottom;
}
.bgTop {
opacity: 0.4;
}
.waveTop {
background-size: 50% 45px;
}
.waveAnimation .waveTop {
animation: move_wave 4s linear infinite;
}
.bgMiddle {
opacity: 0.6;
}
.waveMiddle {
background-size: 50% 40px;
}
.waveAnimation .waveMiddle {
animation: move_wave 3.5s linear infinite;
}
.bgBottom {
opacity: 0.95;
}
.waveBottom {
background-size: 50% 35px;
}
.waveAnimation .waveBottom {
animation: move_wave 2s linear infinite;
}
/* 组件导航列表 start*/
.nav-list {
display: flex;
flex-wrap: wrap;
padding: 0rpx 12rpx 0rpx;
justify-content: space-between;
animation: suspension 3s ease-in-out infinite;
/* 列表元素 start */
.nav-list-item {
padding: 30rpx 30rpx 20rpx 30rpx;
border-radius: 12rpx;
width: 45%;
margin: 0 18rpx 40rpx;
background-size: cover;
background-position: 50%;
position: relative;
z-index: 99;
/* 元素标题 start */
.nav-link {
font-size: 32rpx;
line-height: 1.2;
text-transform: capitalize;
padding: 0rpx 10rpx 0rpx 0;
position: relative;
.title {
color: #FFFFFF;
text-align: left;
}
}
/* 元素标题 end */
/* 元素图标 start */
.icon {
font-variant: small-caps;
width: 70rpx;
height: 70rpx;
line-height: 70rpx;
margin: 0;
padding: 0;
display: inline-flex;
text-align: center;
justify-content: center;
vertical-align: middle;
font-size: 45rpx;
color: #FFFFFF;
white-space: nowrap;
opacity: 0.9;
background-color: rgba(0, 0, 0, 0.05);
background-size: cover;
background-position: 50%;
border-radius: 5000rpx;
}
/* 元素图标 end */
}
/* 列表元素 end */
}
/* 组件导航列表 end*/
</style>
灯光属性分析 | 灯光使用时长分析 |
---|---|
3.3 影刀RPA操作手机遥控器实现灯具互联
影刀RPA
是一款基于Python
自动化组件的桌面流程可视化操作平台
。基于它,我们可以不用写一行python代码就可以实现像机器人一样去自动执行手机或者电脑的多种功能操作!
为了实现小程序与台灯的数据交互,我们在不熟悉嵌入式编程的困境下,可以借助外在的物理条件实现物物信息交流
,这里我们使用手机中的万能遥控器
对台灯进行发号施令! ,从而间接实现小程序与台灯的信息交流
!
- 影刀RPA手机操作功能如下:
手机开启自动化连接操作步骤:
四、推荐阅读
?入门和进阶小程序开发,不可错误的精彩内容? :