desc:气体相关

main
xiaowusky 1 year ago
parent b531e9da31
commit 1c0126af47

@ -13,10 +13,10 @@ const val DEFAULT_QUERY_TIME_INTERVAL = ONE_HOUR_MS * 6
const val CAMERA_URL = "rtsp://admin:123456@192.168.5.200:554/h264/ch1/main/av_stream"
//打开摄像头延时
const val DELAY_TIME_OPEN_CAMERA = 10
const val DELAY_TIME_OPEN_CAMERA = 30
//检测重连摄像头延时
const val DELAY_TIME_CHECK_CAMERA = 5
const val DELAY_TIME_CHECK_CAMERA = DELAY_TIME_OPEN_CAMERA
//检测重连传感器延时
const val DELAY_TIME_CHECK_SENSOR = 5

@ -1,36 +1,66 @@
package com.yinuo.safetywatcher.watcher.port
import com.yinuo.safetywatcher.watcher.port.cmd.C02
import com.yinuo.safetywatcher.watcher.port.cmd.CH4
import com.yinuo.safetywatcher.watcher.port.cmd.CH4_LEL2PPMFACTOR
import com.yinuo.safetywatcher.watcher.port.cmd.CL2
import com.yinuo.safetywatcher.watcher.port.cmd.CO
import com.yinuo.safetywatcher.watcher.port.cmd.H2
import com.yinuo.safetywatcher.watcher.port.cmd.H2S
//气体浓度单位转换系数
const val TEMPERATURE_COEFFICIENT: Float = (273 + 25) / 273f
import com.yinuo.safetywatcher.watcher.port.cmd.H2_LEL2PPMFACTOR
import com.yinuo.safetywatcher.watcher.port.cmd.HF
import com.yinuo.safetywatcher.watcher.port.cmd.MOLECULAR_C02
import com.yinuo.safetywatcher.watcher.port.cmd.MOLECULAR_CH4
import com.yinuo.safetywatcher.watcher.port.cmd.MOLECULAR_CL2
import com.yinuo.safetywatcher.watcher.port.cmd.MOLECULAR_CO
import com.yinuo.safetywatcher.watcher.port.cmd.MOLECULAR_H2
import com.yinuo.safetywatcher.watcher.port.cmd.MOLECULAR_H2S
import com.yinuo.safetywatcher.watcher.port.cmd.MOLECULAR_HF
import com.yinuo.safetywatcher.watcher.port.cmd.MOLECULAR_NH3
import com.yinuo.safetywatcher.watcher.port.cmd.MOLECULAR_NO
import com.yinuo.safetywatcher.watcher.port.cmd.MOLECULAR_NO2
import com.yinuo.safetywatcher.watcher.port.cmd.MOLECULAR_S02
import com.yinuo.safetywatcher.watcher.port.cmd.NH3
import com.yinuo.safetywatcher.watcher.port.cmd.NO
import com.yinuo.safetywatcher.watcher.port.cmd.NO2
import com.yinuo.safetywatcher.watcher.port.cmd.S02
// ppm转mgm3转化率
const val PPM_TO_MGM3_CONVERSION_RATE = 0.0409f
// 后缀
const val MIN_SUFFIX = "min"
const val MAX_SUFFIX = "max"
// 各个气体报警高低默认值,默认单位
// ppm -1代表不考虑低值
const val CO_MIN = -1f
// 20mg/m3
const val CO_MAX_MGM3 = 20f
//vol
const val CO_MIN_MGM3 = 20f
const val CO_MAX_MGM3 = 40f
const val O2_MIN = 19.5f
const val O2_MAX = 23.5f
//lel
const val CH4_MIN = -1f
const val CH4_MAX_LEL = 25f
//ppm
const val H2S_MIN = -1f
// 10mg/m3
const val H2S_MAX_MGM3 = 10f
const val CH4_MIN_LEL = 25f
const val CH4_MAX_LEL = 50f
const val H2S_MIN_MGM3 = 10f
const val H2S_MAX_MGM3 = 20f
const val H2_MIN_LEL = 25f
const val H2_MAX_LEL = 50f
const val NH3_MIN_MGM3 = 20f
const val NH3_MAX_MGM3 = 40f
const val S02_MIN_MGM3 = 5f
const val S02_MAX_MGM3 = 10f
const val CL2_MIN_MGM3 = 1f
const val CL2_MAX_MGM3 = 2f
const val NO2_MIN_MGM3 = 5f
const val NO2_MAX_MGM3 = 10f
const val NO_MIN_PPM = 10f
const val NO_MAX_PPM = 20f
const val HF_MIN_PPM = 2.2f
const val HF_MAX_PPM = 4.4f
const val C02_MIN_PPM = 1000f
const val C02_MAX_PPM = 2000f
//?? TODO VOCS
const val VOCS_MIN_MGM3 = 0.5f
const val VOCS_MAX_MGM3 = 1f
// 单位
const val UNIT_VOL = "%VOL"
@ -38,28 +68,6 @@ const val UNIT_PPM = "ppm"
const val UNIT_MGM3 = "mg/m3"
const val UNIT_LEL = "%LEL"
/**
* 气体分子质量
*/
const val MOLECULAR_CO = 28
const val MOLECULAR_H2S = 34
const val MOLECULAR_CH4 = 16
const val MOLECULAR_O2 = 32
const val MOLECULAR_H2 = 2
const val MOLECULAR_NH3 = 17
const val MOLECULAR_S02 = 64
const val MOLECULAR_CL2 = 71
const val MOLECULAR_NO2 = 46
const val MOLECULAR_NO = 30
const val MOLECULAR_HF = 20
const val MOLECULAR_C02 = 44
val molecular_map = hashMapOf<String, Int>(
Pair(CO, MOLECULAR_CO),
Pair(CH4, MOLECULAR_CH4),
Pair(H2S, MOLECULAR_H2S),
)
/**
* ppm单位的气体量程
*/
@ -77,14 +85,14 @@ val gas_range_ppm = hashMapOf<String, String>(
* C污染物以 ppm 表示的浓度值
* M污染物的分之子量
*
* CO分子量 = 28 28/22.4 * 1000
* CH4分子量 = 16 16/22.4 * 50000
* H2S分子量 = 34 34/22.4 * 100
* CO分子量 = 28 28 * 1000 * PPM_TO_MGM3_CONVERSION_RATE
* CH4分子量 = 16 16 * 50000 * PPM_TO_MGM3_CONVERSION_RATE
* H2S分子量 = 34 34 * 100 * PPM_TO_MGM3_CONVERSION_RATE
*/
val gas_range_mgm3 = hashMapOf<String, String>(
Pair(CO, "0-1250 $UNIT_MGM3"),
Pair(CH4, "0-35714 $UNIT_MGM3"),
Pair(H2S, "0-151 $UNIT_MGM3")
Pair(CO, "0-1145.2 $UNIT_MGM3"),
Pair(CH4, "0-32720 $UNIT_MGM3"),
Pair(H2S, "0-139.06 $UNIT_MGM3")
)
/**
@ -92,25 +100,62 @@ val gas_range_mgm3 = hashMapOf<String, String>(
*/
const val O2_RANGE = "0-30 $UNIT_VOL"
/**
* 氧气的量程 TODO
*/
const val VOCS_RANGE = "0-30 $UNIT_VOL"
// 气体默认阈值表
val default_threshold_map_ppm = hashMapOf<String, Float>(
Pair("${CO}_$MIN_SUFFIX", CO_MIN),
Pair("${CO}_$MIN_SUFFIX", mgm3ToPpm(CO_MIN_MGM3, MOLECULAR_CO)),
Pair("${CO}_$MAX_SUFFIX", mgm3ToPpm(CO_MAX_MGM3, MOLECULAR_CO)),
Pair("${CH4}_$MIN_SUFFIX", CH4_MIN),
Pair("${CH4}_$MAX_SUFFIX", ch4Lel2ppm(CH4_MAX_LEL)),
Pair("${H2S}_$MIN_SUFFIX", H2S_MIN),
Pair("${H2S}_$MAX_SUFFIX", mgm3ToPpm(H2S_MAX_MGM3, MOLECULAR_H2S))
Pair("${CH4}_$MIN_SUFFIX", lel2ppm(CH4_MIN_LEL, CH4_LEL2PPMFACTOR)),
Pair("${CH4}_$MAX_SUFFIX", lel2ppm(CH4_MAX_LEL, CH4_LEL2PPMFACTOR)),
Pair("${H2S}_$MIN_SUFFIX", mgm3ToPpm(H2S_MIN_MGM3, MOLECULAR_H2S)),
Pair("${H2S}_$MAX_SUFFIX", mgm3ToPpm(H2S_MAX_MGM3, MOLECULAR_H2S)),
Pair("${H2}_$MIN_SUFFIX", lel2ppm(H2_MIN_LEL, H2_LEL2PPMFACTOR)),
Pair("${H2}_$MAX_SUFFIX", lel2ppm(H2_MAX_LEL, H2_LEL2PPMFACTOR)),
Pair("${NH3}_$MIN_SUFFIX", mgm3ToPpm(NH3_MIN_MGM3, MOLECULAR_NH3)),
Pair("${NH3}_$MAX_SUFFIX", mgm3ToPpm(NH3_MAX_MGM3, MOLECULAR_NH3)),
Pair("${S02}_$MIN_SUFFIX", mgm3ToPpm(S02_MIN_MGM3, MOLECULAR_S02)),
Pair("${S02}_$MAX_SUFFIX", mgm3ToPpm(S02_MAX_MGM3, MOLECULAR_S02)),
Pair("${CL2}_$MIN_SUFFIX", mgm3ToPpm(CL2_MIN_MGM3, MOLECULAR_CL2)),
Pair("${CL2}_$MAX_SUFFIX", mgm3ToPpm(CL2_MAX_MGM3, MOLECULAR_CL2)),
Pair("${NO2}_$MIN_SUFFIX", mgm3ToPpm(NO2_MIN_MGM3, MOLECULAR_NO2)),
Pair("${NO2}_$MAX_SUFFIX", mgm3ToPpm(NO2_MAX_MGM3, MOLECULAR_NO2)),
Pair("${NO}_$MIN_SUFFIX", NO_MIN_PPM),
Pair("${NO}_$MAX_SUFFIX", NO_MAX_PPM),
Pair("${HF}_$MIN_SUFFIX", HF_MIN_PPM),
Pair("${HF}_$MAX_SUFFIX", HF_MAX_PPM),
Pair("${C02}_$MIN_SUFFIX", C02_MIN_PPM),
Pair("${C02}_$MAX_SUFFIX", C02_MAX_PPM),
)
// 气体默认阈值表
val default_threshold_map_mgm3 = hashMapOf<String, Float>(
Pair("${CO}_$MIN_SUFFIX", CO_MIN),
Pair("${CO}_$MIN_SUFFIX", CO_MIN_MGM3),
Pair("${CO}_$MAX_SUFFIX", CO_MAX_MGM3),
Pair("${CH4}_$MIN_SUFFIX", CH4_MIN),
Pair("${CH4}_$MAX_SUFFIX", ppm2mgm3(ch4Lel2ppm(CH4_MAX_LEL), MOLECULAR_CH4)),
Pair("${H2S}_$MIN_SUFFIX", H2S_MIN),
Pair("${H2S}_$MAX_SUFFIX", H2S_MAX_MGM3)
Pair("${CH4}_$MIN_SUFFIX", ppm2mgm3(lel2ppm(CH4_MIN_LEL, CH4_LEL2PPMFACTOR), MOLECULAR_CH4)),
Pair("${CH4}_$MAX_SUFFIX", ppm2mgm3(lel2ppm(CH4_MAX_LEL, CH4_LEL2PPMFACTOR), MOLECULAR_CH4)),
Pair("${H2S}_$MIN_SUFFIX", H2S_MIN_MGM3),
Pair("${H2S}_$MAX_SUFFIX", H2S_MAX_MGM3),
Pair("${H2}_$MIN_SUFFIX", ppm2mgm3(lel2ppm(H2_MIN_LEL, H2_LEL2PPMFACTOR), MOLECULAR_H2)),
Pair("${H2}_$MAX_SUFFIX", ppm2mgm3(lel2ppm(H2_MAX_LEL, H2_LEL2PPMFACTOR), MOLECULAR_H2)),
Pair("${NH3}_$MIN_SUFFIX", NH3_MIN_MGM3),
Pair("${NH3}_$MAX_SUFFIX", NH3_MAX_MGM3),
Pair("${S02}_$MIN_SUFFIX", S02_MIN_MGM3),
Pair("${S02}_$MAX_SUFFIX", S02_MAX_MGM3),
Pair("${CL2}_$MIN_SUFFIX", CL2_MIN_MGM3),
Pair("${CL2}_$MAX_SUFFIX", CL2_MAX_MGM3),
Pair("${NO2}_$MIN_SUFFIX", NO2_MIN_MGM3),
Pair("${NO2}_$MAX_SUFFIX", NO2_MAX_MGM3),
Pair("${NO}_$MIN_SUFFIX", ppm2mgm3(NO_MIN_PPM, MOLECULAR_NO)),
Pair("${NO}_$MAX_SUFFIX", ppm2mgm3(NO_MAX_PPM, MOLECULAR_NO)),
Pair("${HF}_$MIN_SUFFIX", ppm2mgm3(HF_MIN_PPM, MOLECULAR_HF)),
Pair("${HF}_$MAX_SUFFIX", ppm2mgm3(HF_MAX_PPM, MOLECULAR_HF)),
Pair("${C02}_$MIN_SUFFIX", ppm2mgm3(C02_MIN_PPM, MOLECULAR_C02)),
Pair("${C02}_$MAX_SUFFIX", ppm2mgm3(C02_MAX_PPM, MOLECULAR_C02)),
)
val default_threshold_map_unit = hashMapOf<String, HashMap<String, Float>>(

@ -1,10 +1,21 @@
package com.yinuo.safetywatcher.watcher.port
import com.common.commonlib.utils.MMKVUtils
import com.yinuo.safetywatcher.watcher.port.cmd.C02
import com.yinuo.safetywatcher.watcher.port.cmd.CH4
import com.yinuo.safetywatcher.watcher.port.cmd.CL2
import com.yinuo.safetywatcher.watcher.port.cmd.CO
import com.yinuo.safetywatcher.watcher.port.cmd.GasTypeEnum
import com.yinuo.safetywatcher.watcher.port.cmd.H2
import com.yinuo.safetywatcher.watcher.port.cmd.H2S
import com.yinuo.safetywatcher.watcher.port.cmd.HF
import com.yinuo.safetywatcher.watcher.port.cmd.NH3
import com.yinuo.safetywatcher.watcher.port.cmd.NO
import com.yinuo.safetywatcher.watcher.port.cmd.NO2
import com.yinuo.safetywatcher.watcher.port.cmd.O2
import com.yinuo.safetywatcher.watcher.port.cmd.S02
import com.yinuo.safetywatcher.watcher.port.cmd.VOCS
import com.yinuo.safetywatcher.watcher.port.cmd.getGasTypeEnumByDesc
private fun getLowThresHoldKey(gasType: String): String {
return "${gasType.uppercase()}_$MIN_SUFFIX"
@ -20,10 +31,10 @@ private fun getHighThresHoldKey(gasType: String): String {
*/
fun saveLowThreshold(gasType: String, value: Float, localGasUnit: String) {
var localValue = value
if (O2 != gasType && UNIT_MGM3 == localGasUnit) {
val molecular = molecular_map[gasType]
molecular?.let {
localValue = mgm3ToPpm(value, it)
if (O2 != gasType && VOCS != gasType && UNIT_MGM3 == localGasUnit) {
val typeEnum = getGasTypeEnumByDesc(gasType)
if (typeEnum.molecular > 0) {
localValue = mgm3ToPpm(value, typeEnum.molecular)
}
}
MMKVUtils.put(getLowThresHoldKey(gasType), localValue)
@ -35,10 +46,10 @@ fun saveLowThreshold(gasType: String, value: Float, localGasUnit: String) {
*/
fun saveHighThreshold(gasType: String, value: Float, localGasUnit: String) {
var localValue = value
if (O2 != gasType && UNIT_MGM3 == localGasUnit) {
val molecular = molecular_map[gasType]
molecular?.let {
localValue = mgm3ToPpm(value, it)
if (O2 != gasType && VOCS != gasType && UNIT_MGM3 == localGasUnit) {
val typeEnum = getGasTypeEnumByDesc(gasType)
if (typeEnum.molecular > 0) {
localValue = mgm3ToPpm(value, typeEnum.molecular)
}
}
MMKVUtils.put(getHighThresHoldKey(gasType), localValue)
@ -55,12 +66,16 @@ fun getGasLowThreshold(gasType: String, unit: String): Float {
// 氧气特殊处理
if (O2 == gasType) {
return O2_MIN
} else if (VOCS == gasType) {
return VOCS_MIN_MGM3
}
return (default_threshold_map_unit[unit])?.get(lowThresholdKey) ?: -1f
} else {
if (O2 != gasType && UNIT_MGM3 == unit) {
val molecular = molecular_map[gasType]
molecular?.let { localVlaue = ppm2mgm3(localVlaue, it) }
val typeEnum = getGasTypeEnumByDesc(gasType)
if (typeEnum.molecular > 0) {
localVlaue = ppm2mgm3(localVlaue, typeEnum.molecular)
}
}
}
return localVlaue
@ -77,12 +92,16 @@ fun getGasHighThreshold(gasType: String, unit: String): Float {
// 氧气特殊处理
if (O2 == gasType) {
return O2_MAX
} else if (VOCS == gasType) {
return VOCS_MAX_MGM3
}
return (default_threshold_map_unit[unit])?.get(highThresholdKey) ?: -1f
} else {
if (O2 != gasType && UNIT_MGM3 == unit) {
val molecular = molecular_map[gasType]
molecular?.let { localVlaue = ppm2mgm3(localVlaue, it) }
val typeEnum = getGasTypeEnumByDesc(gasType)
if (typeEnum.molecular > 0) {
localVlaue = ppm2mgm3(localVlaue, typeEnum.molecular)
}
}
}
return localVlaue
@ -95,7 +114,8 @@ fun getGasHighThreshold(gasType: String, unit: String): Float {
fun getLocalGasUnit(gasType: String): String {
return when (gasType.uppercase()) {
O2 -> UNIT_VOL
CO, CH4, H2S -> getDefaultUnit(gasType)
VOCS -> UNIT_VOL // TODO
CO, CH4, H2S, H2, NH3, S02, CL2, NO2, NO, HF, C02 -> getDefaultUnit(gasType)
else -> ""
}
}
@ -118,6 +138,8 @@ fun saveGasUnit(gasType: String, unit: String) {
fun getGasRange(gasType: String, gasUnit: String): String {
if (gasType == O2) {
return O2_RANGE
} else if (gasType == VOCS) {
return VOCS_RANGE
} else {
if (gasUnit == UNIT_PPM) {
return gas_range_ppm[gasType] ?: ""
@ -129,79 +151,38 @@ fun getGasRange(gasType: String, gasUnit: String): String {
}
fun ppm2mgm3(ppmValue: Float, molecular: Int): Float {
return ppmValue * molecular / (22.4f * TEMPERATURE_COEFFICIENT)
return ppmValue * molecular * PPM_TO_MGM3_CONVERSION_RATE
}
fun mgm3ToPpm(mValue: Float, molecular: Int): Float {
return mValue * 22.4f * TEMPERATURE_COEFFICIENT / molecular
return mValue / (molecular * PPM_TO_MGM3_CONVERSION_RATE)
}
fun ch4Lel2ppm(lelValue: Float): Float {
return lelValue * 10000 / 20f
fun lel2ppm(lelValue: Float, lel2ppmFactor: Float): Float {
return lelValue * lel2ppmFactor
}
/**
* 传感器返回数据气体浓度 单位转换
* 氧气O2单位固定不用转换
* 其他三种气体可能需要转换
* 氧气O2vocs单位固定不用转换
* 其他气体可能需要转换
*/
fun convertData(
gasType: String,
gasType: GasTypeEnum,
value: Float,
unit: String,
localGasUnit: String
): Float {
var retValue = value
if (CH4 == gasType) {
retValue = convertCH4(unit, value, localGasUnit)
// lel需要先转ppm
if (unit == UNIT_LEL) {
retValue = value * gasType.lel2ppmFactor
}
// h2s 和 co均只有两种可能场景ppm->mgm3 mgm3->ppm
else if (H2S == gasType) {
if (UNIT_MGM3 == localGasUnit) {
retValue = ppm2mgm3(retValue, MOLECULAR_H2S)
} else if (UNIT_PPM == localGasUnit) {
retValue = mgm3ToPpm(retValue, MOLECULAR_H2S)
}
} else if (CO == gasType) {
if (UNIT_MGM3 == localGasUnit) {
retValue = ppm2mgm3(retValue, MOLECULAR_CO)
} else if (UNIT_PPM == localGasUnit) {
retValue = mgm3ToPpm(retValue, MOLECULAR_CO)
}
// 有两种可能场景ppm->mgm3 mgm3->ppm
if (UNIT_MGM3 == localGasUnit) {
retValue = ppm2mgm3(retValue, gasType.molecular)
} else if (UNIT_PPM == localGasUnit) {
retValue = mgm3ToPpm(retValue, gasType.molecular)
}
return retValue
}
/**
* ch4 有三种可能单位 lel ppm mg/m3, 其中lel不会作为localGasUnit
* 三种情况
* 1.lel转ppm或者mgm3
* 2.ppm转mgm3
* 3.mgm3转ppm
*/
private fun convertCH4(
unit: String,
value: Float,
localGasUnit: String
): Float {
var ret = value
if (UNIT_LEL == unit) {
// to ppm
ret = ch4Lel2ppm(value)
// 目标是mg/mg3
if (UNIT_MGM3 == localGasUnit) {
ret = ppm2mgm3(ret, MOLECULAR_CH4)
}
} else if (UNIT_PPM == unit) {
// 目标是mg/mg3
if (UNIT_MGM3 == localGasUnit) {
ret = ppm2mgm3(ret, MOLECULAR_CH4)
}
} else if (UNIT_MGM3 == unit) {
// 目标是mg/mg3
if (UNIT_PPM == localGasUnit) {
ret = mgm3ToPpm(ret, MOLECULAR_CH4)
}
}
return ret
}

@ -10,13 +10,11 @@ import com.common.commonlib.utils.LogUtils
import com.common.serialport.utils.HexUtils
import com.yinuo.safetywatcher.watcher.constant.GAS_CLOUD_UPLOAD_SIZE_ONCE
import com.yinuo.safetywatcher.watcher.net.DevicesApi
import com.yinuo.safetywatcher.watcher.port.cmd.CH4
import com.yinuo.safetywatcher.watcher.port.cmd.CO
import com.yinuo.safetywatcher.watcher.port.cmd.GasPortStatus
import com.yinuo.safetywatcher.watcher.port.cmd.H2S
import com.yinuo.safetywatcher.watcher.port.cmd.GasTypeEnum
import com.yinuo.safetywatcher.watcher.port.cmd.O2
import com.yinuo.safetywatcher.watcher.port.cmd.ResponseHelper
import com.yinuo.safetywatcher.watcher.port.cmd.getGasTypeByCode
import com.yinuo.safetywatcher.watcher.port.cmd.getGasTypeEnumByCode
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
@ -32,7 +30,7 @@ object ParseHelper {
private val devicesApi by lazy {
DevicesApi()
}
private val gasMap = hashMapOf<String, String>()
private val gasMap = hashMapOf<String, Gas>()
fun parse(it: ByteArray) {
try {
@ -40,8 +38,8 @@ object ParseHelper {
LogUtils.v("receive msg, ${HexUtils.byteArrToHex(it)}")
val gasIndex = it[0].toInt()
val status = it[14].toInt()
val gasType = getGasTypeByCode(it[19].toInt())
if (gasType.isEmpty()) {
val gasType = getGasTypeEnumByCode(it[19].toInt())
if (gasType == GasTypeEnum.TYPE_UNKNOW) {
LogUtils.v("receive msg, unknown gas")
return
}
@ -74,7 +72,7 @@ object ParseHelper {
}
}
private fun parseGasData(gasType: String, it: ByteArray) {
private fun parseGasData(type: GasTypeEnum, it: ByteArray) {
val unitHex: String = HexUtils.byteArrToHex(it, 3, 3 + 2)
val unitToLong: Long = HexUtils.hexToLong(unitHex)
// 10000000000000
@ -108,66 +106,118 @@ object ParseHelper {
val rangHex: String = HexUtils.byteArrToHex(it, 11, 11 + 2)
val rangHexLong: Long = HexUtils.hexToLong(rangHex)
LogUtils.w("receive msg 单位转换前 $gasType, 浓度 = $value $unit")
LogUtils.w("receive msg 单位转换前 $type.desc, 浓度 = $value $unit")
//根据单位进行数值转换
val localGasUnit = getLocalGasUnit(gasType)
val localGasUnit = getLocalGasUnit(type.desc)
if (localGasUnit != unit) {
value = convertData(gasType, value, unit, localGasUnit)
LogUtils.w("receive msg 单位转换后 $gasType, 浓度 = $value $localGasUnit")
value = convertData(type, value, unit, localGasUnit)
LogUtils.w("receive msg 单位转换后 $type.desc, 浓度 = $value $localGasUnit")
}
// 存储临时数据
gasMap[gasType] = " : $value $localGasUnit"
// 插入
insertGasData(gasType, value, localGasUnit)
insertGasData(type, value, localGasUnit)
}
private fun setOverlayData() {
val valueCo = gasMap[CO]
val valueCH4 = gasMap[CH4]
val valueO2 = gasMap[O2]
val valueH2S = gasMap[H2S]
val builder: StringBuilder = java.lang.StringBuilder()
valueCo?.let {
builder.append(CO).append(valueCo).append("@")
}
valueCH4?.let {
builder.append(CH4).append(valueCH4).append("@")
}
valueO2?.let {
builder.append(O2).append(valueO2).append("@")
}
valueH2S?.let {
builder.append(H2S).append(valueH2S)
gasMap.forEach { item ->
val gas = item.value
val time = gas.time
// 3S内的数据我们认为有效
if (System.currentTimeMillis() - time <= 3000) {
builder.append(gas.gasName).append(gas.gasValue).append("@")
}
}
// val valueCo = gasMap[CO]
// val valueCH4 = gasMap[CH4]
// val valueO2 = gasMap[O2]
// val valueH2S = gasMap[H2S]
//
// valueCo?.let {
// builder.append(CO).append(valueCo).append("@")
// }
// valueCH4?.let {
// builder.append(CH4).append(valueCH4).append("@")
// }
// valueO2?.let {
// builder.append(O2).append(valueO2).append("@")
// }
// valueH2S?.let {
// builder.append(H2S).append(valueH2S)
// }
TxtOverlay.setShowTip(builder.toString())
}
/**
* 插入气体数据
*/
private fun insertGasData(gasType: String, value: Float, unit: String) {
private fun insertGasData(typeEnum: GasTypeEnum, value: Float, unit: String) {
GlobalScope.launch(Dispatchers.IO) {
// 阈值范围
val min = getGasLowThreshold(gasType, unit)
val max = getGasHighThreshold(gasType, unit)
val min = getGasLowThreshold(typeEnum.desc, unit)
val max = getGasHighThreshold(typeEnum.desc, unit)
// 构造气体数据
val timeMillis = System.currentTimeMillis()
val gas = Gas(timeMillis, gasType, value, unit, min, max)
val gas = Gas(timeMillis, typeEnum.desc, value, unit, min, max)
// 存储临时数据
gasMap[typeEnum.desc] = gas
val gasDao = DBUtils.gasDao()
gasDao.insert(gas)
// 告警处理
val warningDao = DBUtils.warningDao()
val warning = warningDao.findLatestByName(gasType)
dealWarning(typeEnum, value, min, max, unit)
// 设置水印数据
setOverlayData()
// 实时数据上传后台
uploadGasData(gas)
}
}
private suspend fun dealWarning(
typeEnum: GasTypeEnum,
value: Float,
min: Float,
max: Float,
unit: String
) {
// 告警处理
val warningDao = DBUtils.warningDao()
val warning = warningDao.findLatestByName(typeEnum.desc)
// 氧气特殊处理要在min和max之间其他其他大于min(一级告警阈值)或者max(二级告警阈值)均报警max>min。所以判断>min就报警
if (O2 == typeEnum.desc) {
if (value < min || value > max) {
if (warning == null || warning.endTime > 0) {
warningDao.insert(
Warning(
gasType,
typeEnum.desc,
value,
unit,
System.currentTimeMillis(),
min,
max
)
)
} else {
warning.gasValue = value
warningDao.update(warning)
}
} else {
warning?.let {
it.endTime = System.currentTimeMillis()
warningDao.update(it)
}
}
} else {
if (value > min) {
if (warning == null || warning.endTime > 0) {
warningDao.insert(
Warning(
typeEnum.desc,
value,
unit,
System.currentTimeMillis(),
@ -185,12 +235,6 @@ object ParseHelper {
warningDao.update(it)
}
}
// 设置水印数据
setOverlayData()
// 实时数据上传后台
uploadGasData(gas)
}
}
@ -211,24 +255,24 @@ object ParseHelper {
* 更新数据库
*/
@OptIn(DelicateCoroutinesApi::class)
private fun updateGasTypeDb(gasName: String, status: Int) {
private fun updateGasTypeDb(type: GasTypeEnum, status: Int) {
GlobalScope.launch {
val typeDao = DBUtils.gasTypeDao()
val gasType = typeDao.getByName(gasName)
val gasType = typeDao.getByName(type.desc)
gasType?.status = status
typeDao.insert(gasType ?: GasType(gasName, status))
typeDao.insert(gasType ?: GasType(type.desc, status))
}
}
/**
* 启动离线检查
*/
private fun setFlag(index: Int, gasName: String) {
private fun setFlag(index: Int, type: GasTypeEnum) {
var flagRunnable = mPortRunnable[index]
if (flagRunnable != null) {
mHandler.removeCallbacks(flagRunnable)
}
flagRunnable = FlagRunnable(gasName)
flagRunnable = FlagRunnable(type)
mPortRunnable[index] = flagRunnable
// 如果一段时间内没有收到消息,认为连接断开
mHandler.postDelayed(flagRunnable, GasPortUtils.CHECK_TIME)
@ -238,7 +282,7 @@ object ParseHelper {
* 离线检查
*/
class FlagRunnable(
private val gasName: String
private val gasName: GasTypeEnum
) : Runnable {
override fun run() {
updateGasTypeDb(gasName, GasPortStatus.OUTLINE)

@ -1,32 +0,0 @@
package com.yinuo.safetywatcher.watcher.port.cmd
const val CO = "CO"
const val CH4 = "CH4"
const val O2 = "O2"
const val H2S = "H2S"
const val H2 = "H2"
const val NH3 = "NH3"
const val S02 = "S02"
const val CL2 = "CL2"
const val NO2 = "NO2"
const val NO = "NO"
const val HF = "HF"
const val C02 = "C02"
const val VOCs = "VOCs"
enum class GasType(val code: Int, val desc: String) {
TYPE_CO(5, CO),
TYPE_CH4(11, CH4),
TYPE_O2(67, O2),
TYPE_H2S(52, H2S)
}
fun getGasTypeByCode(code: Int): String {
val codes = GasType.values();
codes.forEach {
if (code == it.code) {
return it.desc;
}
}
return ""
}

@ -0,0 +1,77 @@
package com.yinuo.safetywatcher.watcher.port.cmd
const val CO = "CO"
const val CH4 = "CH4"
const val O2 = "O2"
const val H2S = "H2S"
const val H2 = "H2"
const val NH3 = "NH3"
const val S02 = "S02"
const val CL2 = "CL2"
const val NO2 = "NO2"
const val NO = "NO"
const val HF = "HF"
const val C02 = "C02"
const val VOCS = "VOCS"
/**
* 气体分子质量
*/
const val MOLECULAR_CO = 28
const val MOLECULAR_H2S = 34
const val MOLECULAR_CH4 = 16
const val MOLECULAR_O2 = 32
const val MOLECULAR_H2 = 2
const val MOLECULAR_NH3 = 17
const val MOLECULAR_S02 = 64
const val MOLECULAR_CL2 = 71
const val MOLECULAR_NO2 = 46
const val MOLECULAR_NO = 30
const val MOLECULAR_HF = 20
const val MOLECULAR_C02 = 44
const val CH4_LEL2PPMFACTOR = 500f
const val H2S_LEL2PPMFACTOR = 430f
const val H2_LEL2PPMFACTOR = 400f
enum class GasTypeEnum(
val code: Int,
val desc: String,
val molecular: Int = -1,
val lel2ppmFactor: Float = 0f
) {
TYPE_CO(5, CO, MOLECULAR_CO),
TYPE_CH4(11, CH4, MOLECULAR_H2S, CH4_LEL2PPMFACTOR),
TYPE_O2(67, O2, MOLECULAR_CH4),
TYPE_H2S(52, H2S, MOLECULAR_O2, H2S_LEL2PPMFACTOR),
TYPE_H2(52, H2, MOLECULAR_H2, H2_LEL2PPMFACTOR),
TYPE_NH3(52, NH3, MOLECULAR_NH3),
TYPE_S02(52, S02, MOLECULAR_S02),
TYPE_CL2(52, CL2, MOLECULAR_CL2),
TYPE_NO2(52, NO2, MOLECULAR_NO2),
TYPE_NO(52, NO, MOLECULAR_NO),
TYPE_HF(52, HF, MOLECULAR_HF),
TYPE_C02(52, C02, MOLECULAR_C02),
TYPE_VOCS(52, VOCS),
TYPE_UNKNOW(-1, "UNKNOW")
}
fun getGasTypeEnumByCode(code: Int): GasTypeEnum {
val codes = GasTypeEnum.values();
codes.forEach {
if (code == it.code) {
return it;
}
}
return GasTypeEnum.TYPE_UNKNOW
}
fun getGasTypeEnumByDesc(desc: String): GasTypeEnum {
val codes = GasTypeEnum.values();
codes.forEach {
if (desc == it.desc) {
return it;
}
}
return GasTypeEnum.TYPE_UNKNOW
}

@ -14,6 +14,7 @@ import com.yinuo.safetywatcher.databinding.ActivityQueryDataBinding
import com.yinuo.safetywatcher.watcher.base.BaseActivity
import com.yinuo.safetywatcher.watcher.constant.DEFAULT_QUERY_TIME_INTERVAL
import com.yinuo.safetywatcher.watcher.constant.TimeStep
import com.yinuo.safetywatcher.watcher.port.cmd.getGasTypeEnumByDesc
import com.yinuo.safetywatcher.watcher.port.convertData
import com.yinuo.safetywatcher.watcher.port.getLocalGasUnit
import com.yinuo.safetywatcher.watcher.ui.adapter.HistoryDataAdapter
@ -218,7 +219,8 @@ class QueryDataActivity : BaseActivity() {
val localGasUnit = getLocalGasUnit(it.gasName)
val unit = it.unit
if (unit != localGasUnit) {
it.gasValue = convertData(it.gasName, it.gasValue, unit, localGasUnit)
val typeEnum = getGasTypeEnumByDesc(it.gasName)
it.gasValue = convertData(typeEnum, it.gasValue, unit, localGasUnit)
it.unit = localGasUnit
}
return it

@ -14,7 +14,10 @@ class WarnDataAdapter :
BaseRvAdapter.BaseViewHolder<Warning, LayoutItemWarnBinding>(binding) {
override fun bindView(data: Warning) {
binding.tvTime.text = formatTime(data.startTime)
binding.tvSensor.text = "${data.gasName}浓度异常,${data.gasValue} ${data.unit}"
val standardStr =
if (data.gasValue > data.thresholdHigh) "超过高报警值${data.thresholdHigh}" else "超过低报警值${data.thresholdLow}"
binding.tvSensor.text =
"${data.gasName}浓度异常,${data.gasValue} ${data.unit}$standardStr"
}
private fun formatTime(time: Long): CharSequence? {

Loading…
Cancel
Save