11
unionpi_tiger/sample_hzu/IFPS/IFPS-APP/.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
/node_modules
|
||||
/oh_modules
|
||||
/local.properties
|
||||
/.idea
|
||||
**/build
|
||||
/.hvigor
|
||||
.cxx
|
||||
/.clangd
|
||||
/.clang-format
|
||||
/.clang-tidy
|
||||
**/.test
|
24
unionpi_tiger/sample_hzu/IFPS/IFPS-APP/AppScope/app.json5
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2023 Unionman Technology Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
{
|
||||
"app": {
|
||||
"bundleName": "com.example.ifpclient",
|
||||
"vendor": "example",
|
||||
"versionCode": 1000000,
|
||||
"versionName": "1.0.0",
|
||||
"icon": "$media:app_icon",
|
||||
"label": "$string:app_name"
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "app_name",
|
||||
"value": "IFPClient"
|
||||
}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 2.0 KiB |
49
unionpi_tiger/sample_hzu/IFPS/IFPS-APP/build-profile.json5
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2023 Unionman Technology Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
{
|
||||
"app": {
|
||||
"signingConfigs": [],
|
||||
"compileSdkVersion": 9,
|
||||
"compatibleSdkVersion": 9,
|
||||
"products": [
|
||||
{
|
||||
"name": "default",
|
||||
"signingConfig": "default",
|
||||
}
|
||||
],
|
||||
"buildModeSet": [
|
||||
{
|
||||
"name": "debug",
|
||||
},
|
||||
{
|
||||
"name": "release"
|
||||
}
|
||||
]
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"name": "entry",
|
||||
"srcPath": "./entry",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
6
unionpi_tiger/sample_hzu/IFPS/IFPS-APP/entry/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/node_modules
|
||||
/oh_modules
|
||||
/.preview
|
||||
/build
|
||||
/.cxx
|
||||
/.test
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2023 Unionman Technology Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
{
|
||||
"apiType": "stageMode",
|
||||
"buildOption": {
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"name": "ohosTest",
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
|
||||
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"license": "",
|
||||
"devDependencies": {},
|
||||
"author": "",
|
||||
"name": "entry",
|
||||
"description": "Please describe the basic information.",
|
||||
"main": "",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2023 Unionman Technology Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
|
||||
import hilog from '@ohos.hilog';
|
||||
import UIAbility from '@ohos.app.ability.UIAbility';
|
||||
import Want from '@ohos.app.ability.Want';
|
||||
import window from '@ohos.window';
|
||||
|
||||
export default class EntryAbility extends UIAbility {
|
||||
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
|
||||
}
|
||||
|
||||
onDestroy(): void {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
|
||||
}
|
||||
|
||||
onWindowStageCreate(windowStage: window.WindowStage): void {
|
||||
// Main window is created, set main page for this ability
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
|
||||
|
||||
windowStage.loadContent('pages/Index', (err) => {
|
||||
if (err.code) {
|
||||
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
|
||||
return;
|
||||
}
|
||||
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
|
||||
});
|
||||
}
|
||||
|
||||
onWindowStageDestroy(): void {
|
||||
// Main window is destroyed, release UI related resources
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
|
||||
}
|
||||
|
||||
onForeground(): void {
|
||||
// Ability has brought to foreground
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
|
||||
}
|
||||
|
||||
onBackground(): void {
|
||||
// Ability has back to background
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
|
||||
}
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2023 Unionman Technology Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import data_rdb from '@ohos.data.rdb'
|
||||
|
||||
const STORE_CONFIG = {name: 'test.db'}
|
||||
const TAB_LOG = 'log'
|
||||
|
||||
const CREATE_TABLE_LOG_CODE = `
|
||||
CREATE TABLE IF NOT EXISTS ${TAB_LOG} (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date TEXT,
|
||||
level TEXT,
|
||||
info TEXT
|
||||
)
|
||||
`
|
||||
type logItem = {
|
||||
time: string;
|
||||
level: string;
|
||||
info :string;
|
||||
}
|
||||
|
||||
export function createTable(context: Context) {
|
||||
data_rdb.getRdbStore(context, STORE_CONFIG, 1, function (err, rdbStore) {
|
||||
if(err){
|
||||
console.log('ERROR: Get RdbStore failed, err: ' + err)
|
||||
return
|
||||
}
|
||||
rdbStore.executeSql(CREATE_TABLE_LOG_CODE, [], function(err) {
|
||||
if (err) {
|
||||
console.log('ERROR: ExecuteSql failed, err: ' + err)
|
||||
return
|
||||
}
|
||||
console.log('SUCCESS: create table done.')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function insertData(context: Context, item: logItem): Promise<void> {
|
||||
const promise = data_rdb.getRdbStore(context, STORE_CONFIG, 1)
|
||||
return promise.then(async (rdbStore) => {
|
||||
try{
|
||||
console.log(`insert : ${item.time}`)
|
||||
rdbStore.insert(TAB_LOG, item)
|
||||
}catch (err){
|
||||
console.log('ERROR: insert failed: ' + err)
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log('ERROR: Get RdbStore failed, err: ' + err)
|
||||
})
|
||||
}
|
||||
|
||||
export function insertDataArr(context: Context, list: logItem[]): Promise<void> {
|
||||
const promise = data_rdb.getRdbStore(context, STORE_CONFIG, 1);
|
||||
return promise.then(async (rdbStore) => {
|
||||
for (let i: number = 0; i < list.length; i++) {
|
||||
const value = {
|
||||
date: list[i].time,
|
||||
level: list[i].level,
|
||||
info: list[i].info,
|
||||
};
|
||||
try {
|
||||
console.log(`insert ${i}: ${list[i].time}`);
|
||||
await rdbStore.insert(TAB_LOG, value);
|
||||
} catch (err) {
|
||||
console.log('ERROR: insert failed: ' + err);
|
||||
}
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.log('ERROR: Get RdbStore failed, err: ' + err);
|
||||
});
|
||||
}
|
||||
|
||||
export function queryData(context: Context,
|
||||
page: number,
|
||||
indexOffset: number,
|
||||
pageSize: number): Promise<logItem[] | false> {
|
||||
let promise = data_rdb.getRdbStore(context, STORE_CONFIG, 1)
|
||||
return promise.then(async (rdbStore) => {
|
||||
// 查询操作
|
||||
const offset: number = (page - 1) * pageSize + indexOffset;
|
||||
const querySqlString = `SELECT * FROM ${TAB_LOG} ORDER BY date DESC LIMIT ${pageSize} OFFSET ${offset}`
|
||||
|
||||
try {
|
||||
let resultSet = await rdbStore.querySql(querySqlString, [])
|
||||
if (resultSet.rowCount == 0) {
|
||||
return false
|
||||
}
|
||||
let list: logItem[] = []
|
||||
resultSet.goToFirstRow()
|
||||
for (let i = 0; i < resultSet.rowCount; i++) {
|
||||
const time = resultSet.getString(resultSet.getColumnIndex('date'))
|
||||
const level = resultSet.getString(resultSet.getColumnIndex('level'))
|
||||
const info = resultSet.getString(resultSet.getColumnIndex('info'))
|
||||
resultSet.goToNextRow()
|
||||
const data: logItem = { time, level, info }
|
||||
list.push(data)
|
||||
console.log(`query success ${i} : ${time}`)
|
||||
}
|
||||
resultSet.close()
|
||||
return list
|
||||
} catch (err) {
|
||||
console.log('ERROR: query failed, err: ' + err)
|
||||
return false
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error('ERROR: Get RdbStore failed, err: ' + err)
|
||||
return false
|
||||
})
|
||||
}
|
@ -0,0 +1,825 @@
|
||||
/*
|
||||
* Copyright 2023 Unionman Technology Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {createTable, insertData, queryData} from './DBManager'
|
||||
import systemDateTime from '@ohos.systemDateTime';
|
||||
import display from '@ohos.display'
|
||||
|
||||
// @ts-ignore
|
||||
import ifpsnapidemo from '@ohos.ifpsnapidemo';
|
||||
|
||||
import prompt from '@ohos.prompt';
|
||||
|
||||
type device = {
|
||||
deviceName: string;
|
||||
value: string;
|
||||
status: boolean;
|
||||
};
|
||||
|
||||
type logItem = {
|
||||
time: string;
|
||||
level: string;
|
||||
info :string;
|
||||
}
|
||||
|
||||
@Entry
|
||||
@Component
|
||||
struct Home {
|
||||
|
||||
@State systemStatus: number = 0
|
||||
@State pwm1_start :boolean = false
|
||||
@State pwm2_start :boolean = false
|
||||
@State flameSensorThreshold: number = 23
|
||||
private flameSensorStatus: Boolean = false
|
||||
@State smokeSensorThreshold: number = 16
|
||||
private smokeSensorStatus: Boolean = false
|
||||
@State temperatureThreshold: number = 50
|
||||
private temperatureStatus: Boolean = false
|
||||
@State humidityThreshold: number = 30
|
||||
private humidityStatus: Boolean = false
|
||||
|
||||
private controller_tabs : TabsController = new TabsController()
|
||||
private controller_dialog1: CustomDialogController = new CustomDialogController({
|
||||
builder: CustomDialogValueInput({
|
||||
textValue: this.flameSensorThreshold,
|
||||
inputValue: $flameSensorThreshold,
|
||||
})
|
||||
})
|
||||
private controller_dialog2: CustomDialogController = new CustomDialogController({
|
||||
builder: CustomDialogValueInput({
|
||||
textValue: this.smokeSensorThreshold,
|
||||
inputValue: $smokeSensorThreshold,
|
||||
})
|
||||
})
|
||||
private controller_dialog3: CustomDialogController = new CustomDialogController({
|
||||
builder: CustomDialogValueInput({
|
||||
textValue: this.temperatureThreshold,
|
||||
inputValue: $temperatureThreshold,
|
||||
})
|
||||
})
|
||||
private controller_dialog4: CustomDialogController = new CustomDialogController({
|
||||
builder: CustomDialogValueInput({
|
||||
textValue: this.humidityThreshold,
|
||||
inputValue: $humidityThreshold,
|
||||
})
|
||||
})
|
||||
private displayClass: display.Display | null = null
|
||||
private dpi: number = 160
|
||||
|
||||
@State logListData: Array<logItem> = []
|
||||
private devicesData: Array<device> = []
|
||||
@State gridData: Array<device> = []
|
||||
@State page: number = 1
|
||||
private pageSize: number = 20
|
||||
private indexOffset: number = 0
|
||||
|
||||
aboutToAppear() {
|
||||
this.init()
|
||||
console.log(this.page.toString())
|
||||
}
|
||||
|
||||
init() {
|
||||
// 获得屏幕信息
|
||||
try {
|
||||
this.displayClass = display.getDefaultDisplaySync();
|
||||
this.dpi = this.displayClass.densityDPI
|
||||
console.log('Test densityDPI:' + JSON.stringify(this.displayClass.densityDPI));
|
||||
} catch (exception) {
|
||||
console.error('Failed to obtain the default display object. Code: ' + JSON.stringify(exception));
|
||||
}
|
||||
// 数据初始化
|
||||
createTable(getContext(this))
|
||||
this.query()
|
||||
this.update()
|
||||
// 启动定时器
|
||||
setInterval(this.update.bind(this), 3000)
|
||||
}
|
||||
|
||||
update() {
|
||||
while(this.devicesData.length > 0) {
|
||||
this.devicesData.pop()
|
||||
}
|
||||
|
||||
// 获取ppm(烟雾浓度)
|
||||
const fPpmValue = getPPMValue()
|
||||
if(fPpmValue){
|
||||
const ppmValue = fPpmValue
|
||||
const ppmValueString = fPpmValue.toFixed(3)
|
||||
const deviceStatus = ppmValue > this.smokeSensorThreshold
|
||||
if(deviceStatus && !this.smokeSensorStatus) {
|
||||
this.smokeSensorStatus = true
|
||||
this.addData('2', '检测到可燃气体,二级警报!')
|
||||
} else if(!deviceStatus && this.smokeSensorStatus) {
|
||||
this.smokeSensorStatus = false
|
||||
}
|
||||
this.devicesData.push({'deviceName': '烟雾传感器', 'value': ppmValueString, 'status': deviceStatus})
|
||||
}
|
||||
|
||||
// 获取火焰传感器 adc值
|
||||
const fFireValue = getFIREValue();
|
||||
if(fFireValue){
|
||||
const fireValue = fFireValue
|
||||
const fireValueString = fFireValue.toFixed(3)
|
||||
const deviceStatus = fireValue < this.flameSensorThreshold
|
||||
if(deviceStatus && !this.flameSensorStatus) {
|
||||
this.flameSensorStatus = true
|
||||
this.addData('1', '检测到火焰,一级警报!')
|
||||
// 自动开启舵机
|
||||
this.pwm1_start = true
|
||||
|
||||
} else if(!deviceStatus && this.flameSensorStatus) {
|
||||
this.flameSensorStatus = false
|
||||
this.pwm1_start = false
|
||||
}
|
||||
this.devicesData.push({'deviceName': '火焰传感器', 'value': fireValueString, 'status': deviceStatus})
|
||||
}
|
||||
|
||||
// 温湿度
|
||||
const fSensorData = readTemperatureAndHumidity()
|
||||
if(fSensorData) {
|
||||
const temperatureValue = fSensorData.temperatureC
|
||||
const temperatureValueString = temperatureValue.toFixed(3)
|
||||
const deviceStatus1 = temperatureValue > this.temperatureThreshold
|
||||
if(deviceStatus1 && !this.temperatureStatus) {
|
||||
this.temperatureStatus = true
|
||||
this.addData('3', `温度高于${this.temperatureThreshold},三级警报!`)
|
||||
} else if(!deviceStatus1 && this.temperatureStatus) {
|
||||
this.temperatureStatus = false
|
||||
}
|
||||
this.devicesData.push({'deviceName': '温度传感器', 'value': temperatureValueString, 'status': deviceStatus1})
|
||||
|
||||
const humidityValue = fSensorData.humidity
|
||||
const humidityValueString = fSensorData.humidity.toFixed(3)
|
||||
const deviceStatus2 = humidityValue < this.humidityThreshold
|
||||
if(deviceStatus2 && !this.humidityStatus) {
|
||||
this.humidityStatus = true
|
||||
this.addData('3', `湿度低于${this.humidityThreshold},三级警报!`)
|
||||
} else if(!deviceStatus2 && this.humidityStatus) {
|
||||
this.humidityStatus = false
|
||||
}
|
||||
this.devicesData.push({'deviceName': '湿度传感器', 'value': humidityValueString, 'status': deviceStatus2})
|
||||
}
|
||||
|
||||
this.devicesData.push({'deviceName': '舵机', 'value': 'none', 'status': false})
|
||||
this.devicesData.push({'deviceName': '蜂鸣器', 'value': 'none', 'status': false})
|
||||
|
||||
// 更新主页警告状态
|
||||
if(this.flameSensorStatus) {
|
||||
this.systemStatus = 1
|
||||
} else if(this.smokeSensorStatus) {
|
||||
this.systemStatus = 2
|
||||
} else if(this.temperatureStatus || this.humidityStatus) {
|
||||
this.systemStatus = 3
|
||||
} else {
|
||||
this.systemStatus = 0
|
||||
}
|
||||
// 更新数据
|
||||
this.gridData = this.devicesData
|
||||
}
|
||||
|
||||
addData(sLevel: string, sInfo: string) {
|
||||
getTimeString().then(sTime => {
|
||||
const item: logItem = {time: sTime, level: sLevel, info: sInfo}
|
||||
insertData(getContext(this), item).then(() => {
|
||||
// 更新列表
|
||||
console.log(`update: ${JSON.stringify(item)}`);
|
||||
this.indexOffset++
|
||||
this.logListData.unshift(item)
|
||||
// 弹窗警告
|
||||
AlertDialog.show(
|
||||
{
|
||||
title: '警告!',
|
||||
message: sInfo,
|
||||
autoCancel: true,
|
||||
alignment: DialogAlignment.Bottom,
|
||||
offset: { dx: 0, dy: -20 },
|
||||
gridCount: 3
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
query() {
|
||||
queryData(getContext(this), this.page, this.indexOffset, this.pageSize)
|
||||
.then(data => {
|
||||
if(data){
|
||||
if(this.page === 1) {
|
||||
this.logListData = data
|
||||
} else {
|
||||
this.logListData = this.logListData.concat(data)
|
||||
}
|
||||
this.page++
|
||||
} else {
|
||||
console.log('now last page')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Builder buildLogList() {
|
||||
Row() {
|
||||
this.buildLogo()
|
||||
if(this.logListData.length != 0) {
|
||||
List({space: 20, initialIndex: 0}) {
|
||||
ForEach(this.logListData, (item) => {
|
||||
ListItem() {
|
||||
Row(){
|
||||
// 警告等级数字
|
||||
Text(item.level)
|
||||
.width('30%')
|
||||
.fontSize(this.dpi / 2.5)
|
||||
.fontColor(getTextColor(Number(item.level)))
|
||||
.textAlign(TextAlign.Center)
|
||||
// 警告内容
|
||||
Column(){
|
||||
Text(item.date)
|
||||
.fontSize(this.dpi / 5)
|
||||
.fontColor(Color.Black)
|
||||
.textAlign(TextAlign.Center)
|
||||
.padding({bottom: 5})
|
||||
Text(item.info)
|
||||
.fontSize(this.dpi / 4)
|
||||
.maxLines(2)
|
||||
.textOverflow({overflow:TextOverflow.Ellipsis})
|
||||
}
|
||||
.width('70%')
|
||||
.padding({right:'5%'})
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.justifyContent(FlexAlign.Start)
|
||||
}
|
||||
.height('20%')
|
||||
.alignItems(VerticalAlign.Center)
|
||||
.justifyContent(FlexAlign.Center)
|
||||
.backgroundColor('#f5f5f5')
|
||||
.borderRadius(10)
|
||||
}.editable(true)
|
||||
})
|
||||
}
|
||||
.width('60%')
|
||||
.height('80%')
|
||||
//.divider({strokeWidth:1, color:Color.Grey, startMargin:20, endMargin:20})
|
||||
.onReachEnd( () => {
|
||||
console.log(`now page ${this.page}`)
|
||||
this.query()
|
||||
})
|
||||
} else {
|
||||
Text('empty')
|
||||
.fontColor('#708090')
|
||||
.fontSize(this.dpi / 4)
|
||||
.textAlign(TextAlign.Center)
|
||||
.height('80%')
|
||||
.width('60%')
|
||||
}
|
||||
}
|
||||
}
|
||||
@Builder buildGrid() {
|
||||
Row() {
|
||||
this.buildLogo()
|
||||
Grid(){
|
||||
ForEach(this.gridData, (item, index) => {
|
||||
GridItem(){
|
||||
Column(){
|
||||
Text(`${item.deviceName}`)
|
||||
.fontSize(this.dpi / 5)
|
||||
.fontColor(Color.Black)
|
||||
.textAlign(TextAlign.Center)
|
||||
.padding({top: '3%'})
|
||||
.height('30%')
|
||||
|
||||
Column(){
|
||||
// 火焰传感器 & 烟雾传感器
|
||||
if(index === 0 || index === 1) {
|
||||
Stack() {
|
||||
Column() {
|
||||
// 状态显示
|
||||
Text(`${getStatusText(item.status)}`)
|
||||
.fontColor(getStatusTextColor(item.status))
|
||||
.fontSize(this.dpi / 4)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
// 数据显示
|
||||
Text(String(item.value))
|
||||
.fontSize(this.dpi / 4)
|
||||
.fontColor(getStatusTextColor(item.status))
|
||||
.padding({top: '2%'})
|
||||
}
|
||||
.width('100%')
|
||||
|
||||
Column() {
|
||||
// 阈值设置
|
||||
Button({ type: ButtonType.Circle, stateEffect: false })
|
||||
.height(this.dpi / 4).width(this.dpi / 4)
|
||||
.backgroundColor('#00000000')
|
||||
.backgroundImage($r('app.media.ic_public_settings'))
|
||||
.backgroundImageSize({ width: '100%', height: '100%' })
|
||||
.onClick(() => {
|
||||
// 弹窗
|
||||
if(index === 1) {
|
||||
this.controller_dialog1.open()
|
||||
} else {
|
||||
this.controller_dialog2.open()
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('90%').height('90%')
|
||||
.justifyContent(FlexAlign.End)
|
||||
.alignItems(HorizontalAlign.End)
|
||||
}
|
||||
} else if(index === 2 || index === 3) {
|
||||
Stack() {
|
||||
if(index === 2) {
|
||||
Text(`${item.value}°C`)
|
||||
.fontSize(this.dpi / 3)
|
||||
.fontColor(getNumberTextColor(item.value, this.temperatureThreshold))
|
||||
.padding('5%')
|
||||
} else {
|
||||
Text(`${item.value}%`)
|
||||
.fontSize(this.dpi / 3)
|
||||
.fontColor(getNumberTextColor(item.value, this.humidityThreshold))
|
||||
.padding('5%')
|
||||
}
|
||||
Column() {
|
||||
// 阈值设置
|
||||
Button({ type: ButtonType.Circle, stateEffect: false })
|
||||
.height(this.dpi / 4).width(this.dpi / 4)
|
||||
.backgroundColor('#00000000')
|
||||
.backgroundImage($r('app.media.ic_public_settings'))
|
||||
.backgroundImageSize({ width: '100%', height: '100%' })
|
||||
.onClick(() => {
|
||||
// 弹窗
|
||||
if(index === 2) {
|
||||
this.controller_dialog3.open()
|
||||
} else {
|
||||
this.controller_dialog4.open()
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('90%').height('90%')
|
||||
.justifyContent(FlexAlign.End)
|
||||
.alignItems(HorizontalAlign.End)
|
||||
}
|
||||
} else if(index === 4) {
|
||||
// 舵机开关
|
||||
Row() {
|
||||
Toggle({ type: ToggleType.Switch, isOn: this.pwm1_start })
|
||||
.size({ width: '35%', height: '35%' })
|
||||
.onChange((isChecked) => {
|
||||
this.pwm1_start = isChecked
|
||||
if(isChecked) {
|
||||
prompt.showToast({
|
||||
message: '打开舵机', // 显示文本
|
||||
})
|
||||
try {
|
||||
ifpsnapidemo.SetPwmStatus(1, 90)
|
||||
console.log(`SetPwmStatus ${isChecked}}`)
|
||||
}catch(err) {
|
||||
console.log('ERROR: SetPwmStatus failed' + err)
|
||||
}
|
||||
} else {
|
||||
prompt.showToast({
|
||||
message: '关闭舵机', // 显示文本
|
||||
})
|
||||
try {
|
||||
ifpsnapidemo.SetPwmStatus(1, 0)
|
||||
console.log(`SetPwmStatus ${isChecked}}`)
|
||||
}catch(err) {
|
||||
console.log('ERROR: SetPwmStatus failed' + err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.padding({ top: '3%' })
|
||||
.justifyContent(FlexAlign.Center)
|
||||
} else if(index === 5){
|
||||
// 蜂鸣器开关
|
||||
Row() {
|
||||
Toggle({ type: ToggleType.Switch, isOn: this.pwm2_start })
|
||||
.size({ width: '35%', height: '35%' })
|
||||
.onChange((isChecked) => {
|
||||
this.pwm2_start = !this.pwm2_start
|
||||
if(isChecked) {
|
||||
prompt.showToast({
|
||||
message: '打开蜂鸣器',
|
||||
})
|
||||
try {
|
||||
ifpsnapidemo.SetPwmStatus(2, 90)
|
||||
console.log(`setPwmStatus ${isChecked}}`)
|
||||
}catch(err) {
|
||||
console.log('ERROR: setPwmStatus failed' + err)
|
||||
}
|
||||
} else {
|
||||
prompt.showToast({
|
||||
message: '关闭蜂鸣器',
|
||||
})
|
||||
try {
|
||||
ifpsnapidemo.SetPwmStatus(2, -90)
|
||||
console.log(`SetPwmStatus ${isChecked}}`)
|
||||
}catch(err) {
|
||||
console.log('ERROR: SetPwmStatus failed' + err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.padding({ top: '3%' })
|
||||
.justifyContent(FlexAlign.Center)
|
||||
}
|
||||
}
|
||||
.height('65%').width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
.width('100%')
|
||||
.backgroundColor('#f7f7f7')
|
||||
.borderRadius(10)
|
||||
}
|
||||
})
|
||||
}
|
||||
.columnsTemplate('1fr 1fr')
|
||||
.rowsTemplate('1fr 1fr 1fr')
|
||||
.columnsGap(10)
|
||||
.rowsGap(10)
|
||||
.height('80%')
|
||||
.width('60%')
|
||||
}
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
@Builder buildLogo() {
|
||||
Column(){
|
||||
Column(){
|
||||
// 标题
|
||||
Text('OpenHarmony')
|
||||
.fontColor(Color.Blue)
|
||||
.fontSize(this.dpi / 2)
|
||||
.fontStyle(FontStyle.Italic)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
.fontFamily('Arial')
|
||||
.width('100%')
|
||||
.textAlign(TextAlign.Center)
|
||||
.padding({top:'30%'})
|
||||
.margin({bottom:10})
|
||||
|
||||
Text('智能消防系统')
|
||||
.fontColor(Color.Black)
|
||||
.fontSize(this.dpi / 2)
|
||||
.fontFamily('SimHei')
|
||||
.width('100%')
|
||||
.textAlign(TextAlign.Center)
|
||||
.padding( {bottom: '20%'} )
|
||||
}
|
||||
.width('90%')
|
||||
.height('80%')
|
||||
.backgroundColor('#f5f5f5')
|
||||
.borderRadius(10)
|
||||
}
|
||||
.width('40%')
|
||||
.height('100%')
|
||||
.justifyContent(FlexAlign.Center)
|
||||
.alignItems(HorizontalAlign.Center)
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
@Builder buildHomePage() {
|
||||
Row(){
|
||||
this.buildLogo()
|
||||
Column(){
|
||||
Column(){
|
||||
Text('消防监控系统目前')
|
||||
.fontColor(Color.Black)
|
||||
.fontSize(this.dpi / 4)
|
||||
.textAlign(TextAlign.Center)
|
||||
Text(getStatusText(this.systemStatus))
|
||||
.fontColor(getTextColor(this.systemStatus))
|
||||
.fontSize(this.dpi / 2)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
.padding({top: '5%'})
|
||||
}
|
||||
.backgroundColor(getStatusBackgroundColor(this.systemStatus))
|
||||
.width('90%')
|
||||
.height('50%')
|
||||
.justifyContent(FlexAlign.Center)
|
||||
.alignItems(HorizontalAlign.Center)
|
||||
.borderRadius(10)
|
||||
.margin( {top: '2%'} )
|
||||
|
||||
// 报警按钮
|
||||
Button('一键报警', { type: ButtonType.Normal, stateEffect: true })
|
||||
.onClick(() => {
|
||||
// 报警弹窗
|
||||
AlertDialog.show(
|
||||
{
|
||||
title: '警告',
|
||||
message: '即将报警,是否确认?',
|
||||
autoCancel: true,
|
||||
alignment: DialogAlignment.Bottom,
|
||||
gridCount: 4,
|
||||
offset: { dx: 0, dy: -20 },
|
||||
primaryButton: {
|
||||
value: '取消',
|
||||
action: () => {
|
||||
console.info('取消报警')
|
||||
}
|
||||
},
|
||||
secondaryButton: {
|
||||
value: '确认',
|
||||
action: () => {
|
||||
console.info('已报警')
|
||||
}
|
||||
},
|
||||
cancel: () => {
|
||||
console.info('Closed callbacks')
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
.width('90%')
|
||||
.height('35%')
|
||||
.fontSize(this.dpi / 3)
|
||||
.fontColor(Color.Red)
|
||||
.backgroundColor(Color.Yellow)
|
||||
.borderRadius(10)
|
||||
.margin( {top: '5%'} )
|
||||
}
|
||||
.width('60%')
|
||||
.height('80%')
|
||||
.alignItems(HorizontalAlign.Center)
|
||||
}
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
|
||||
build() {
|
||||
Column(){
|
||||
|
||||
// 导航栏组件
|
||||
Tabs({ barPosition: BarPosition.End, controller: this.controller_tabs }){
|
||||
// 首页
|
||||
TabContent(){
|
||||
this.buildHomePage()
|
||||
}
|
||||
.tabBar('首页')
|
||||
|
||||
// 消防页面
|
||||
TabContent(){
|
||||
Column(){
|
||||
this.buildGrid()
|
||||
}
|
||||
}
|
||||
.tabBar('消防')
|
||||
|
||||
// 日志页面
|
||||
TabContent(){
|
||||
Column(){
|
||||
// 日志信息列表
|
||||
this.buildLogList()
|
||||
}
|
||||
.backgroundColor(Color.White)
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
.tabBar('日志')
|
||||
}
|
||||
.barWidth('100%')
|
||||
.barHeight('15%')
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor(0xF5F5F5)
|
||||
.vertical(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CustomDialog
|
||||
struct CustomDialogValueInput {
|
||||
@Link inputValue: number
|
||||
private textValue: number
|
||||
controller?: CustomDialogController
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Text('更新警报阈值:').fontSize(20).margin({ top: 10, bottom: 10 })
|
||||
TextInput({ placeholder: '', text: this.inputValue.toString() }).height(60).width('90%')
|
||||
.type(InputType.Number)
|
||||
.onChange((value: string) => {
|
||||
this.textValue = Number(value)
|
||||
})
|
||||
Text('是否确认修改?').fontSize(16).margin({ bottom: 10 }).padding({top: 20})
|
||||
Flex({ justifyContent: FlexAlign.SpaceAround }) {
|
||||
Button('取消')
|
||||
.onClick(() => {
|
||||
this.controller.close()
|
||||
}).backgroundColor(0xffffff).fontColor(Color.Black)
|
||||
Button('确认')
|
||||
.onClick(() => {
|
||||
if (this.controller != undefined) {
|
||||
this.inputValue = this.textValue
|
||||
this.controller.close()
|
||||
prompt.showToast({
|
||||
message: `成功更新警报阈值为${this.inputValue}`,
|
||||
})
|
||||
}
|
||||
}).backgroundColor(0xffffff).fontColor(Color.Red)
|
||||
}.margin({ bottom: 10 })
|
||||
}.borderRadius(10)
|
||||
}
|
||||
}
|
||||
|
||||
function getTextColor(x: number){
|
||||
if(x === 1) {
|
||||
return Color.Red
|
||||
}
|
||||
if(x === 2) {
|
||||
return '#ffca3230'
|
||||
}
|
||||
if(x === 3) {
|
||||
return '#c55c2d'
|
||||
} else {
|
||||
return Color.Green
|
||||
}
|
||||
}
|
||||
function getStatusBackgroundColor(x: number) {
|
||||
if(x > 0) {
|
||||
return '#dfea50'
|
||||
} else {
|
||||
return '#98ff98'
|
||||
}
|
||||
}
|
||||
function getStatusText(x: number){
|
||||
if(x === 0) {
|
||||
return '正常'
|
||||
} else {
|
||||
return '异常'
|
||||
}
|
||||
}
|
||||
function getStatusTextColor(x: Boolean){
|
||||
if(x) {
|
||||
return Color.Red
|
||||
} else {
|
||||
return Color.Green
|
||||
}
|
||||
}
|
||||
function getNumberTextColor(x: number, y: number){
|
||||
if(x > y) {
|
||||
return Color.Red
|
||||
}
|
||||
return '#708090'
|
||||
}
|
||||
|
||||
function getTimeString(): any {
|
||||
const promise = systemDateTime.getCurrentTime(false)
|
||||
return promise.then(timestamp => {
|
||||
const currentTime: Date = new Date(timestamp);
|
||||
const year: number = currentTime.getFullYear();
|
||||
const month: number = currentTime.getMonth() + 1;
|
||||
const day: number = currentTime.getDate();
|
||||
const hours: number = currentTime.getHours();
|
||||
const minutes: number = currentTime.getMinutes();
|
||||
const seconds: number = currentTime.getSeconds();
|
||||
|
||||
// 将数字转换为两位数的字符串形式(补0)
|
||||
const padZero = (num: number): string => {
|
||||
return num < 10 ? '0' + num : num.toString()
|
||||
}
|
||||
|
||||
// 构建字符串
|
||||
const formattedTime: string = `${year}-${padZero(month)}-${padZero(day)} ${padZero(hours)}:${padZero(minutes)}:${padZero(seconds)}`;
|
||||
return formattedTime
|
||||
}).catch(err => {
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
// 函数:读取温湿度数据
|
||||
function readTemperatureAndHumidity() {
|
||||
// 调用传感器软重启函数
|
||||
const softResetResult = ifpsnapidemo.Sht3xSoftReset();
|
||||
console.log('Sensor Sht3xSoft Reset Result:', softResetResult);
|
||||
|
||||
// 设置传感器测量模式
|
||||
const mps = 2; // 2Hz
|
||||
const repeatability = 1; // 中刷新率
|
||||
const modeSetResult = ifpsnapidemo.Sht3xModeSet(mps, repeatability);
|
||||
console.log('Sensor Sht3xMode Set Result:', modeSetResult);
|
||||
|
||||
// 读取温湿度数据
|
||||
const readDataResult = ifpsnapidemo.Sht3xReadData();
|
||||
console.log('Read Sht3xReadData Result:', readDataResult);
|
||||
|
||||
// 使用下列三个接口时必须先调用ReadData
|
||||
if (readDataResult === 0) {
|
||||
// 读取摄氏温度
|
||||
const temperatureC = ifpsnapidemo.Sht3xReadTemperatureC();
|
||||
|
||||
// 读取华氏温度
|
||||
const temperatureF = ifpsnapidemo.Sht3xReadTemperatureF();
|
||||
|
||||
// 读取湿度
|
||||
const humidity = ifpsnapidemo.Sht3xReadHumidity();
|
||||
|
||||
return {
|
||||
temperatureC,
|
||||
temperatureF,
|
||||
humidity
|
||||
};
|
||||
} else {
|
||||
console.log('Failed to read data. Please check the sensor connection and try again.');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getPPMValue() {
|
||||
// 获取 ADC 值
|
||||
let adcValue = 20
|
||||
try {
|
||||
adcValue = ifpsnapidemo.Mq2GetAdcValue();
|
||||
}catch (err) {
|
||||
console.log('ERROR: Mq2GetAdcValue failed.');
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查是否需要权限
|
||||
if (adcValue < 0) {
|
||||
let permissionGranted = ifpsnapidemo.Mq2GetPermission();
|
||||
|
||||
// 检查权限获取结果
|
||||
if (!permissionGranted) {
|
||||
console.error('无法获取 ADC 值并且权限获取失败');
|
||||
return null; // 返回 null 表示无法获取 ppm 值
|
||||
}
|
||||
|
||||
// 再次尝试获取 ADC 值
|
||||
try {
|
||||
adcValue = ifpsnapidemo.Mq2GetAdcValue();
|
||||
}catch (err) {
|
||||
console.log('ERROR: Mq2GetAdcValue failed.');
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查是否成功获取 ADC 值
|
||||
if (adcValue < 0) {
|
||||
console.error('无法获取 ADC 值');
|
||||
return null; // 返回 null 表示无法获取 ppm 值
|
||||
}
|
||||
}
|
||||
|
||||
// 计算电压值(伏特)
|
||||
let voltage = adcValue * (3.3 / 4096);
|
||||
|
||||
// 使用特定的公式将电压转换为 ppm 值
|
||||
// 这里使用一个简单的示例,实际上应该根据传感器的特性来计算 ppm 值
|
||||
let ppmValue = voltage * 10; // 假设一个简单的线性关系
|
||||
|
||||
return ppmValue;
|
||||
}
|
||||
function getFIREValue() {
|
||||
// 获取 ADC 值
|
||||
let adcValue = 20
|
||||
try {
|
||||
adcValue = ifpsnapidemo.FlameSensorGetAdcValue();
|
||||
}catch (err) {
|
||||
console.log('ERROR: FlameSensorGetAdcValue failed.');
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查是否需要权限
|
||||
if (adcValue < 0) {
|
||||
let permissionGranted = ifpsnapidemo.FlameSensorGetPermission();
|
||||
|
||||
// 检查权限获取结果
|
||||
if (!permissionGranted) {
|
||||
console.error('无法获取 ADC 值并且权限获取失败');
|
||||
return null; // 返回 null 表示无法获取 ppm 值
|
||||
}
|
||||
|
||||
// 再次尝试获取 ADC 值
|
||||
try {
|
||||
adcValue = ifpsnapidemo.FlameSensorGetAdcValue();
|
||||
}catch (err) {
|
||||
console.log('ERROR: FlameSensorGetAdcValue failed.');
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查是否成功获取 ADC 值
|
||||
if (adcValue < 0) {
|
||||
console.error('无法获取 ADC 值');
|
||||
return null; // 返回 null 表示无法获取 fire 值
|
||||
}
|
||||
}
|
||||
|
||||
// 计算电压值(伏特)
|
||||
let voltage = adcValue * (3.3 / 4096);
|
||||
|
||||
// 使用特定的公式将电压转换为 fire 值
|
||||
// 这里使用一个简单的示例,实际上应该根据传感器的特性来计算 fire 值
|
||||
let fireValue = voltage * 10.0; // 假设一个简单的线性关系
|
||||
|
||||
return fireValue;
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2023 Unionman Technology Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
{
|
||||
"module": {
|
||||
"name": "entry",
|
||||
"type": "entry",
|
||||
"description": "$string:module_desc",
|
||||
"mainElement": "EntryAbility",
|
||||
"deviceTypes": [
|
||||
"default",
|
||||
"tablet"
|
||||
],
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false,
|
||||
"pages": "$profile:main_pages",
|
||||
"abilities": [
|
||||
{
|
||||
"name": "EntryAbility",
|
||||
"srcEntry": "./ets/entryability/EntryAbility.ts",
|
||||
"description": "$string:EntryAbility_desc",
|
||||
"icon": "$media:icon",
|
||||
"label": "$string:EntryAbility_label",
|
||||
"startWindowIcon": "$media:startIcon",
|
||||
"startWindowBackground": "$color:start_window_background",
|
||||
"exported": true,
|
||||
"skills": [
|
||||
{
|
||||
"entities": [
|
||||
"entity.system.home"
|
||||
],
|
||||
"actions": [
|
||||
"action.system.home"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"color": [
|
||||
{
|
||||
"name": "start_window_background",
|
||||
"value": "#FFFFFF"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_desc",
|
||||
"value": "module description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_label",
|
||||
"value": "label"
|
||||
}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 758 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,5 @@
|
||||
{
|
||||
"src": [
|
||||
"pages/Index"
|
||||
]
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_desc",
|
||||
"value": "module description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_label",
|
||||
"value": "label"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_desc",
|
||||
"value": "模块描述"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_desc",
|
||||
"value": "description"
|
||||
},
|
||||
{
|
||||
"name": "EntryAbility_label",
|
||||
"value": "label"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
import hilog from '@ohos.hilog';
|
||||
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
|
||||
|
||||
export default function abilityTest() {
|
||||
describe('ActsAbilityTest', () => {
|
||||
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
|
||||
beforeAll(() => {
|
||||
// Presets an action, which is performed only once before all test cases of the test suite start.
|
||||
// This API supports only one parameter: preset action function.
|
||||
})
|
||||
beforeEach(() => {
|
||||
// Presets an action, which is performed before each unit test case starts.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: preset action function.
|
||||
})
|
||||
afterEach(() => {
|
||||
// Presets a clear action, which is performed after each unit test case ends.
|
||||
// The number of execution times is the same as the number of test cases defined by **it**.
|
||||
// This API supports only one parameter: clear action function.
|
||||
})
|
||||
afterAll(() => {
|
||||
// Presets a clear action, which is performed after all test cases of the test suite end.
|
||||
// This API supports only one parameter: clear action function.
|
||||
})
|
||||
it('assertContain', 0, () => {
|
||||
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
|
||||
let a = 'abc';
|
||||
let b = 'b';
|
||||
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
|
||||
expect(a).assertContain(b);
|
||||
expect(a).assertEqual(a);
|
||||
})
|
||||
})
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
import abilityTest from './Ability.test';
|
||||
|
||||
export default function testsuite() {
|
||||
abilityTest();
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
import UIAbility from '@ohos.app.ability.UIAbility';
|
||||
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
|
||||
import hilog from '@ohos.hilog';
|
||||
import { Hypium } from '@ohos/hypium';
|
||||
import testsuite from '../test/List.test';
|
||||
import window from '@ohos.window';
|
||||
import Want from '@ohos.app.ability.Want';
|
||||
import AbilityConstant from '@ohos.app.ability.AbilityConstant';
|
||||
|
||||
export default class TestAbility extends UIAbility {
|
||||
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:' + JSON.stringify(launchParam) ?? '');
|
||||
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator;
|
||||
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
|
||||
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs;
|
||||
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments();
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
|
||||
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite);
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
|
||||
}
|
||||
|
||||
onWindowStageCreate(windowStage: window.WindowStage) {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
|
||||
windowStage.loadContent('testability/pages/Index', (err) => {
|
||||
if (err.code) {
|
||||
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
|
||||
return;
|
||||
}
|
||||
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
|
||||
});
|
||||
}
|
||||
|
||||
onWindowStageDestroy() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
|
||||
}
|
||||
|
||||
onForeground() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
|
||||
}
|
||||
|
||||
onBackground() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
@Entry
|
||||
@Component
|
||||
struct Index {
|
||||
@State message: string = 'Hello World';
|
||||
|
||||
build() {
|
||||
Row() {
|
||||
Column() {
|
||||
Text(this.message)
|
||||
.fontSize(50)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2023 Unionman Technology Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import hilog from '@ohos.hilog';
|
||||
import TestRunner from '@ohos.application.testRunner';
|
||||
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
|
||||
import Want from '@ohos.app.ability.Want';
|
||||
|
||||
let abilityDelegator: AbilityDelegatorRegistry.AbilityDelegator | undefined = undefined
|
||||
let abilityDelegatorArguments: AbilityDelegatorRegistry.AbilityDelegatorArgs | undefined = undefined
|
||||
|
||||
async function onAbilityCreateCallback() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback');
|
||||
}
|
||||
|
||||
async function addAbilityMonitorCallback(err : Error) {
|
||||
hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
|
||||
}
|
||||
|
||||
export default class OpenHarmonyTestRunner implements TestRunner {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
onPrepare() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare ');
|
||||
}
|
||||
|
||||
async onRun() {
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run');
|
||||
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
|
||||
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
|
||||
const bundleName = abilityDelegatorArguments.bundleName;
|
||||
const testAbilityName = 'TestAbility';
|
||||
const moduleName = abilityDelegatorArguments.parameters['-m'];
|
||||
let lMonitor: AbilityDelegatorRegistry.AbilityMonitor = {
|
||||
abilityName: testAbilityName,
|
||||
onAbilityCreate: onAbilityCreateCallback,
|
||||
moduleName: moduleName
|
||||
};
|
||||
abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
|
||||
const want: Want = {
|
||||
bundleName: bundleName,
|
||||
abilityName: testAbilityName,
|
||||
moduleName: moduleName
|
||||
};
|
||||
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator();
|
||||
abilityDelegator.startAbility(want, (err, data) => {
|
||||
hilog.info(0x0000, 'testTag', 'startAbility : err : %{public}s', JSON.stringify(err) ?? '');
|
||||
hilog.info(0x0000, 'testTag', 'startAbility : data : %{public}s',JSON.stringify(data) ?? '');
|
||||
})
|
||||
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end');
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2023 Unionman Technology Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
{
|
||||
"module": {
|
||||
"name": "entry_test",
|
||||
"type": "feature",
|
||||
"description": "$string:module_test_desc",
|
||||
"mainElement": "TestAbility",
|
||||
"deviceTypes": [
|
||||
"default",
|
||||
"tablet"
|
||||
],
|
||||
"deliveryWithInstall": true,
|
||||
"installationFree": false,
|
||||
"pages": "$profile:test_pages",
|
||||
"abilities": [
|
||||
{
|
||||
"name": "TestAbility",
|
||||
"srcEntry": "./ets/testability/TestAbility.ets",
|
||||
"description": "$string:TestAbility_desc",
|
||||
"icon": "$media:icon",
|
||||
"label": "$string:TestAbility_label",
|
||||
"exported": true,
|
||||
"startWindowIcon": "$media:icon",
|
||||
"startWindowBackground": "$color:start_window_background",
|
||||
"skills": [
|
||||
{
|
||||
"actions": [
|
||||
"action.system.home"
|
||||
],
|
||||
"entities": [
|
||||
"entity.system.home"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
{
|
||||
"color": [
|
||||
{
|
||||
"name": "start_window_background",
|
||||
"value": "#FFFFFF"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "module_test_desc",
|
||||
"value": "test ability description"
|
||||
},
|
||||
{
|
||||
"name": "TestAbility_desc",
|
||||
"value": "the test ability"
|
||||
},
|
||||
{
|
||||
"name": "TestAbility_label",
|
||||
"value": "test label"
|
||||
}
|
||||
]
|
||||
}
|
After Width: | Height: | Size: 2.0 KiB |
@ -0,0 +1,5 @@
|
||||
{
|
||||
"src": [
|
||||
"testability/pages/Index"
|
||||
]
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
"hvigorVersion": "3.2.4",
|
||||
"dependencies": {
|
||||
"@ohos/hvigor-ohos-plugin": "3.2.4"
|
||||
},
|
||||
"execution": {
|
||||
// "analyze": "default", /* Define the build analyze mode. Value: [ "default" | "verbose" | false ]. Default: "default" */
|
||||
// "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */
|
||||
// "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */
|
||||
// "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */
|
||||
// "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */
|
||||
},
|
||||
"logging": {
|
||||
// "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
|
||||
},
|
||||
"debugging": {
|
||||
// "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */
|
||||
},
|
||||
"nodeOptions": {
|
||||
// "maxOldSpaceSize": 4096 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process */
|
||||
}
|
||||
}
|
6
unionpi_tiger/sample_hzu/IFPS/IFPS-APP/hvigorfile.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { appTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
|
||||
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
|
||||
}
|
54
unionpi_tiger/sample_hzu/IFPS/IFPS-APP/hvigorw
Normal file
@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Hvigor startup script, version 1.0.0
|
||||
#
|
||||
# Required ENV vars:
|
||||
# ------------------
|
||||
# NODE_HOME - location of a Node home dir
|
||||
# or
|
||||
# Add /usr/local/nodejs/bin to the PATH environment variable
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
HVIGOR_APP_HOME="`pwd -P`"
|
||||
HVIGOR_WRAPPER_SCRIPT=${HVIGOR_APP_HOME}/hvigor/hvigor-wrapper.js
|
||||
#NODE_OPTS="--max-old-space-size=4096"
|
||||
|
||||
fail() {
|
||||
echo "$*"
|
||||
exit 1
|
||||
}
|
||||
|
||||
set_executable_node() {
|
||||
EXECUTABLE_NODE="${NODE_HOME}/bin/node"
|
||||
if [ -x "$EXECUTABLE_NODE" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
EXECUTABLE_NODE="${NODE_HOME}/node"
|
||||
if [ -x "$EXECUTABLE_NODE" ]; then
|
||||
return
|
||||
fi
|
||||
fail "ERROR: NODE_HOME is set to an invalid directory,check $NODE_HOME\n\nPlease set NODE_HOME in your environment to the location where your nodejs installed"
|
||||
}
|
||||
|
||||
# Determine node to start hvigor wrapper script
|
||||
if [ -n "${NODE_HOME}" ]; then
|
||||
set_executable_node
|
||||
else
|
||||
EXECUTABLE_NODE="node"
|
||||
command -v ${EXECUTABLE_NODE} &> /dev/null || fail "ERROR: NODE_HOME not set and 'node' command not found"
|
||||
fi
|
||||
|
||||
# Check hvigor wrapper script
|
||||
if [ ! -r "$HVIGOR_WRAPPER_SCRIPT" ]; then
|
||||
fail "ERROR: Couldn't find hvigor/hvigor-wrapper.js in ${HVIGOR_APP_HOME}"
|
||||
fi
|
||||
|
||||
if [ -z "${NODE_OPTS}" ]; then
|
||||
NODE_OPTS="--"
|
||||
fi
|
||||
|
||||
# start hvigor-wrapper script
|
||||
exec "${EXECUTABLE_NODE}" "${NODE_OPTS}" \
|
||||
"${HVIGOR_WRAPPER_SCRIPT}" "$@"
|
After Width: | Height: | Size: 125 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 7.3 KiB |
After Width: | Height: | Size: 556 KiB |
After Width: | Height: | Size: 462 KiB |
After Width: | Height: | Size: 541 KiB |
After Width: | Height: | Size: 502 KiB |
After Width: | Height: | Size: 502 KiB |
202
unionpi_tiger/sample_hzu/IFPS/README.md
Normal file
@ -0,0 +1,202 @@
|
||||
### IFPS
|
||||
|
||||
### **作品简介**
|
||||
|
||||
基于OpenHarmony的智能消防系统,实现对温湿度的监测,可燃气体及火焰的检测,对应设置三级警报,使用舵机模拟自动灭火设备的开关,蜂鸣器实现报警功能。
|
||||
|
||||
### **开发环境简介**
|
||||
|
||||
1、搭载OpenHarmony-4.0-Beat5版本的Unionpi Tiger开发板
|
||||
|
||||
2、DevEco Studio 4.0.0.600
|
||||
|
||||
3、温湿度模块SHT3x-DIS
|
||||
|
||||
4、烟雾传感器MQ-2
|
||||
|
||||
5、火焰传感器FC-01
|
||||
|
||||
6、MG996R舵机
|
||||
|
||||
7、无源蜂鸣器
|
||||
|
||||
### 温湿度传感器数据采集
|
||||
|
||||
通过IIC协议进行数据的采集
|
||||
|
||||
### 烟雾传感器数据采集
|
||||
|
||||
通过ADC通道1采集ADC值,使用转换公式转换获取烟雾浓度,例程中仅使用简单的线性转换
|
||||
|
||||
### 火焰传感器数据采集
|
||||
|
||||
通过ADC通道2采集ADC值,通过转换获取到的电压值判断是否检测到火焰
|
||||
|
||||
### 蜂鸣器控制
|
||||
|
||||
使用PWM控制蜂鸣器,以发出不同频率的声音,对应不同的警报等级
|
||||
|
||||
### 舵机控制
|
||||
|
||||
使用PWM控制舵机,通过调整占空比以控制舵机转动角度
|
||||
|
||||
### NAPI
|
||||
|
||||
全称 Native API,是OpenHarmony系统中的一套原生模块拓展开发框架,基于N-API开发,为开发者提供了JS与C/C++不同语言模块之间的相互访问,交互的能力。它可以用于规范化封装IO、OS底层等,并可以提供相应的JS接口供开发者调用。
|
||||
|
||||
#### 编写子系统组件
|
||||
|
||||
在vendor/unionman/unionpi_tiger/sample/napi/napisubsys目录下新建ifpsnapidemo文件夹。
|
||||
|
||||
##### 文件目录
|
||||
|
||||
![image-20240623135533871](README.assets/image-20240623135533871.png)
|
||||
|
||||
##### 编写ifpsnapidemo.cpp文件
|
||||
|
||||
##### 编写GN构建脚本
|
||||
|
||||
ifpsnapidemo/BUILD.gn
|
||||
|
||||
```json
|
||||
|
||||
import("//build/ohos.gni")
|
||||
|
||||
config("warns") {
|
||||
cflags = [ "-Werror" ]
|
||||
}
|
||||
|
||||
ohos_shared_library("ifpsnapidemo") {
|
||||
include_dirs = [
|
||||
"//foundation/ace/napi/interfaces/kits",
|
||||
"//commonlibrary/c_utils/base/include",
|
||||
"//base/hiviewdfx/hilog/interfaces/native/innerkits/include",
|
||||
]
|
||||
|
||||
sources = [
|
||||
"i2cinterface.c",
|
||||
"ifpsnapidemo.cpp",
|
||||
"sample_client.c",
|
||||
"um_adc.c",
|
||||
"um_pwm.c",
|
||||
]
|
||||
|
||||
configs = [ ":warns" ]
|
||||
|
||||
external_deps = [
|
||||
"c_utils:utils",
|
||||
"hilog:libhilog",
|
||||
"napi:ace_napi",
|
||||
]
|
||||
|
||||
part_name = "product_unionpi_tiger"
|
||||
}
|
||||
|
||||
ohos_executable("sample_server") {
|
||||
output_name = "sample_server_executable"
|
||||
sources = [ "sample_server.c" ]
|
||||
include_dirs = [ "//base/hiviewdfx/hilog/interfaces/native/innerkits/include" ]
|
||||
configs = [ ":warns" ]
|
||||
external_deps = [
|
||||
"c_utils:utils",
|
||||
"hilog:libhilog",
|
||||
]
|
||||
install_images = [ "system" ]
|
||||
}
|
||||
```
|
||||
|
||||
##### 修改配置
|
||||
|
||||
ohos4.0release/vendor/unionman/unionpi_tiger/bundle.json
|
||||
|
||||
![image-20240623131529188](README.assets/image-20240623131529188.png)
|
||||
|
||||
ohos4.0release/vendor/unionman/unionpi_tiger/sample/BUILD.gn
|
||||
|
||||
![image-20240623131648032](README.assets/image-20240623131648032.png)
|
||||
|
||||
#### 编写TS接口定义文件
|
||||
|
||||
编写好NAPI代码之后,需要编写TS接口定义文件(.d.ts),这样开发OpenHarmony应用时,编译器才知道模块定义了哪些函数以及对应的返回值,参数列表等。
|
||||
|
||||
@ohos.ifpsnapidemo.d.ts
|
||||
|
||||
```ts
|
||||
declare namespace ifpsnapidemo {
|
||||
|
||||
// 传感器软重启
|
||||
function Sht3xSoftReset(): number;
|
||||
|
||||
/**
|
||||
* 设置传感器测量模式
|
||||
* @param mps 取值为[0,3] 对应mps=0.5、1、2、4、10Hz
|
||||
* @param repeatability 取值为[0,2] 对应低刷新率、中刷新率、高刷新率
|
||||
*/
|
||||
function Sht3xModeSet(mps: number, repeatability: number): number;
|
||||
|
||||
// 读取温湿度数据
|
||||
function Sht3xReadData(): number;
|
||||
// 使用下列三个接口时必须先调用ReadData
|
||||
function Sht3xReadTemperatureC(): number;
|
||||
function Sht3xReadHumidity(): number;
|
||||
function Sht3xReadTemperatureF(): number;
|
||||
|
||||
function Mq2GetAdcValue(): number;
|
||||
function Mq2GetPermission(): number;
|
||||
|
||||
function FlameSensorGetAdcValue(): number;
|
||||
function FlameSensorGetPermission(): number;
|
||||
|
||||
/**
|
||||
* 设置pwm的开关状态
|
||||
* @param pwmPex pwm引脚
|
||||
* @param pwmAngle pwm角度
|
||||
*/
|
||||
function SetPwmStatus(pwmPex: number, pwmAngle: number): Promise<number>;
|
||||
}
|
||||
|
||||
export default ifpsnapidemo;
|
||||
```
|
||||
|
||||
### 构建
|
||||
|
||||
进入OpenHarmony源代码的根目录,执行编译
|
||||
|
||||
```shell
|
||||
./build.sh --product-name unionpi_tiger –ccache
|
||||
```
|
||||
|
||||
如果开发板已经烧录了同版本的OpenHarmony操作系统,可以在out/unionpi_tiger/[子系统名]/[组件名]文件夹中找到组件对应的动态库,然后使用hdc工具发送到开发板的/system/lib/module目录中即可,省去了烧录所花的时间
|
||||
|
||||
```shell
|
||||
hdc_std file send libxxx.z.so /system/lib/module
|
||||
```
|
||||
|
||||
在发送时,可能出现以下错误
|
||||
|
||||
[Fail]Error opening file: read-only file system, path:/system/lib/module/libxxx.z.so
|
||||
|
||||
这是因为system分区被开机挂载为只读分区,解决方案是重新挂载system分区为可读写分区
|
||||
|
||||
```shell
|
||||
hdc_std shell mount / -o rw,remount
|
||||
```
|
||||
|
||||
然后再重新发送动态库至开发板即可
|
||||
|
||||
### 编译用户程序
|
||||
|
||||
1、往对应版本的SDK中添加自定义的ifpsnapidemo.d.ts 文件
|
||||
|
||||
2、使用DevEco Studio打开项目文件夹IFPS-APP
|
||||
|
||||
3、添加自动签名
|
||||
|
||||
4、执行编译
|
||||
|
||||
### 演示效果
|
||||
|
||||
| 首页 | 状态 | 日志 |
|
||||
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
|
||||
| ![image-20240701121821873.png](README.assets/image-20240701121821873.png) | ![image-20240701121856786](README.assets/image-20240701121856786.png) | ![image-20240702132100441](README.assets/image-20240702132100441.png) |
|
||||
|