Merge pull request !314 from jiang-jh/master
This commit is contained in:
openharmony_ci 2024-07-15 01:54:11 +00:00 committed by Gitee
commit b1465d6de6
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
44 changed files with 1791 additions and 0 deletions

View File

@ -0,0 +1,11 @@
/node_modules
/oh_modules
/local.properties
/.idea
**/build
/.hvigor
.cxx
/.clangd
/.clang-format
/.clang-tidy
**/.test

View 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"
}
}

View File

@ -0,0 +1,8 @@
{
"string": [
{
"name": "app_name",
"value": "IFPClient"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View 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"
]
}
]
}
]
}

View File

@ -0,0 +1,6 @@
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test

View File

@ -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",
}
]
}

View File

@ -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. */
}

View File

@ -0,0 +1,10 @@
{
"license": "",
"devDependencies": {},
"author": "",
"name": "entry",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}

View File

@ -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');
}
}

View File

@ -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
})
}

View File

@ -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;
}

View File

@ -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"
]
}
]
}
]
}
}

View File

@ -0,0 +1,8 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -0,0 +1,16 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "label"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,5 @@
{
"src": [
"pages/Index"
]
}

View File

@ -0,0 +1,16 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "label"
}
]
}

View File

@ -0,0 +1,16 @@
{
"string": [
{
"name": "module_desc",
"value": "模块描述"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "label"
}
]
}

View File

@ -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);
})
})
}

View File

@ -0,0 +1,5 @@
import abilityTest from './Ability.test';
export default function testsuite() {
abilityTest();
}

View File

@ -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');
}
}

View File

@ -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%')
}
}

View File

@ -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');
}
}

View File

@ -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"
]
}
]
}
]
}
}

View File

@ -0,0 +1,8 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -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"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,5 @@
{
"src": [
"testability/pages/Index"
]
}

View File

@ -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 */
}
}

File diff suppressed because one or more lines are too long

View 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. */
}

View 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}" "$@"

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 541 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 KiB

View 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) |