settings-store.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. const {
  2. toFiniteNumber
  3. } = require('../utils/number-format.js')
  4. const {
  5. clampInteger
  6. } = require('../utils/base-utils.js')
  7. const {
  8. getWxApi
  9. } = require('../utils/platform-utils.js')
  10. const STORAGE_KEY = 'app-settings'
  11. const PROTOCOL_MODE = {
  12. MODBUS_RTU: 'modbus-rtu',
  13. STORAGE_ACCESS: 'storage-access'
  14. }
  15. const LEGACY_PROTOCOL_MODE_ALIASES = {
  16. generic: PROTOCOL_MODE.MODBUS_RTU,
  17. private: PROTOCOL_MODE.STORAGE_ACCESS
  18. }
  19. const PROTOCOL_OPTIONS = [
  20. { key: PROTOCOL_MODE.STORAGE_ACCESS, label: '存储访问' },
  21. { key: PROTOCOL_MODE.MODBUS_RTU, label: '标准Modbus' }
  22. ]
  23. const DEFAULT_SETTINGS = {
  24. modbusSlaveAddress: 'F0',
  25. nightModeEnabled: false,
  26. nightModeFollowSystem: true,
  27. parameterAutoPollEnabled: false,
  28. parameterMaxPacketLength: 64,
  29. parameterPollInterval: 100,
  30. protocolMode: PROTOCOL_MODE.STORAGE_ACCESS
  31. }
  32. const STATUS_POLL_MIN_INTERVAL = 100
  33. const STATUS_POLL_MAX_INTERVAL = 3000
  34. const PARAMETER_MIN_PACKET_LENGTH = 32
  35. const state = {
  36. ...DEFAULT_SETTINGS
  37. }
  38. let initialized = false
  39. const subscribers = []
  40. function normalizeHexByte(value, fallback = DEFAULT_SETTINGS.modbusSlaveAddress) {
  41. const fallbackText = String(fallback || DEFAULT_SETTINGS.modbusSlaveAddress).toUpperCase()
  42. const text = String(value === undefined || value === null ? '' : value).trim()
  43. const hexText = text.toUpperCase().startsWith('0X') ? text.slice(2) : text
  44. if (!/^[0-9A-F]{1,2}$/i.test(hexText)) return fallbackText
  45. return parseInt(hexText, 16).toString(16).toUpperCase().padStart(2, '0')
  46. }
  47. function normalizeParameterPacketLength(value, fallback = DEFAULT_SETTINGS.parameterMaxPacketLength) {
  48. const numberValue = toFiniteNumber(value, NaN)
  49. if (!Number.isFinite(numberValue)) return fallback
  50. const rounded = Math.round(numberValue)
  51. if (rounded <= 0) return 0
  52. return Math.max(rounded, PARAMETER_MIN_PACKET_LENGTH)
  53. }
  54. function normalizeProtocolMode(value) {
  55. const key = String(value || '').trim()
  56. const normalizedKey = LEGACY_PROTOCOL_MODE_ALIASES[key] || key
  57. const matched = PROTOCOL_OPTIONS.find((option) => option.key === key)
  58. if (matched) return matched.key
  59. const normalizedMatched = PROTOCOL_OPTIONS.find((option) => option.key === normalizedKey)
  60. return normalizedMatched ? normalizedMatched.key : DEFAULT_SETTINGS.protocolMode
  61. }
  62. function isModbusProtocol(value = state.protocolMode) {
  63. return normalizeProtocolMode(value) === PROTOCOL_MODE.MODBUS_RTU
  64. }
  65. function isStorageAccessProtocol(value = state.protocolMode) {
  66. return normalizeProtocolMode(value) === PROTOCOL_MODE.STORAGE_ACCESS
  67. }
  68. function parseHexByte(value, label = '从机地址') {
  69. const text = String(value === undefined || value === null ? '' : value).trim()
  70. const hexText = text.toUpperCase().startsWith('0X') ? text.slice(2) : text
  71. if (!/^[0-9A-F]{1,2}$/i.test(hexText)) {
  72. throw new Error(`${label}需为 00 - FF`)
  73. }
  74. return parseInt(hexText, 16)
  75. }
  76. function migrateLegacySettings(settings = {}) {
  77. const hasProtocolMode = settings.protocolMode !== undefined && settings.protocolMode !== null && settings.protocolMode !== ''
  78. const hasParameterAutoPollEnabled = settings.parameterAutoPollEnabled !== undefined
  79. const hasParameterMaxPacketLength = settings.parameterMaxPacketLength !== undefined
  80. const hasParameterPollInterval = settings.parameterPollInterval !== undefined
  81. return {
  82. ...settings,
  83. protocolMode: hasProtocolMode ? settings.protocolMode : settings.modbusProtocolMode,
  84. parameterAutoPollEnabled: hasParameterAutoPollEnabled
  85. ? settings.parameterAutoPollEnabled
  86. : settings.genericModbusAutoPollEnabled,
  87. parameterMaxPacketLength: hasParameterMaxPacketLength
  88. ? settings.parameterMaxPacketLength
  89. : settings.genericModbusMaxPacketLength,
  90. parameterPollInterval: hasParameterPollInterval
  91. ? settings.parameterPollInterval
  92. : settings.genericModbusPollInterval
  93. }
  94. }
  95. function normalizeSettings(settings = {}) {
  96. const migratedSettings = migrateLegacySettings(settings)
  97. const protocolMode = normalizeProtocolMode(migratedSettings.protocolMode)
  98. const parameterAutoPollEnabled = !!migratedSettings.parameterAutoPollEnabled
  99. const parameterMaxPacketLength = normalizeParameterPacketLength(
  100. migratedSettings.parameterMaxPacketLength,
  101. DEFAULT_SETTINGS.parameterMaxPacketLength
  102. )
  103. const parameterPollInterval = clampInteger(
  104. migratedSettings.parameterPollInterval,
  105. STATUS_POLL_MIN_INTERVAL,
  106. STATUS_POLL_MAX_INTERVAL,
  107. DEFAULT_SETTINGS.parameterPollInterval
  108. )
  109. return {
  110. modbusSlaveAddress: normalizeHexByte(migratedSettings.modbusSlaveAddress),
  111. nightModeEnabled: !!migratedSettings.nightModeEnabled,
  112. nightModeFollowSystem: migratedSettings.nightModeFollowSystem !== false,
  113. parameterAutoPollEnabled,
  114. parameterMaxPacketLength,
  115. parameterPollInterval,
  116. protocolMode
  117. }
  118. }
  119. function readStoredSettings() {
  120. const wxApi = getWxApi()
  121. if (typeof wxApi.getStorageSync !== 'function') return {}
  122. try {
  123. return wxApi.getStorageSync(STORAGE_KEY) || {}
  124. } catch (error) {
  125. return {}
  126. }
  127. }
  128. function persistSettings() {
  129. const wxApi = getWxApi()
  130. if (typeof wxApi.setStorageSync !== 'function') return
  131. try {
  132. wxApi.setStorageSync(STORAGE_KEY, getState())
  133. } catch (error) {}
  134. }
  135. function notify() {
  136. const nextState = getState()
  137. subscribers.slice().forEach((subscriber) => {
  138. subscriber(nextState)
  139. })
  140. }
  141. function setState(changedData, options = {}) {
  142. Object.assign(state, normalizeSettings({
  143. ...state,
  144. ...changedData
  145. }))
  146. if (options.persist !== false) {
  147. persistSettings()
  148. }
  149. notify()
  150. }
  151. function init() {
  152. if (initialized) return
  153. Object.assign(state, normalizeSettings(readStoredSettings()))
  154. initialized = true
  155. }
  156. function getState() {
  157. return {
  158. ...state
  159. }
  160. }
  161. function subscribe(subscriber) {
  162. if (typeof subscriber !== 'function') return () => {}
  163. init()
  164. subscribers.push(subscriber)
  165. subscriber(getState())
  166. return () => {
  167. const index = subscribers.indexOf(subscriber)
  168. if (index >= 0) subscribers.splice(index, 1)
  169. }
  170. }
  171. function setNightModeEnabled(value) {
  172. init()
  173. setState({
  174. nightModeEnabled: !!value
  175. })
  176. }
  177. function setNightModeFollowSystem(value) {
  178. init()
  179. setState({
  180. nightModeFollowSystem: !!value
  181. })
  182. }
  183. function setModbusSlaveAddress(value) {
  184. init()
  185. setState({
  186. modbusSlaveAddress: normalizeHexByte(value, state.modbusSlaveAddress)
  187. })
  188. }
  189. function setProtocolMode(value) {
  190. init()
  191. setState({
  192. protocolMode: normalizeProtocolMode(value)
  193. })
  194. }
  195. function getModbusSlaveAddress() {
  196. init()
  197. return parseHexByte(state.modbusSlaveAddress, 'Modbus从机地址')
  198. }
  199. function setParameterAutoPollEnabled(value) {
  200. init()
  201. setState({
  202. parameterAutoPollEnabled: !!value
  203. })
  204. }
  205. function setParameterMaxPacketLength(value) {
  206. init()
  207. setState({
  208. parameterMaxPacketLength: normalizeParameterPacketLength(value, state.parameterMaxPacketLength)
  209. })
  210. }
  211. function setParameterPollInterval(value) {
  212. init()
  213. setState({
  214. parameterPollInterval: value
  215. })
  216. }
  217. module.exports = {
  218. PARAMETER_MIN_PACKET_LENGTH,
  219. PROTOCOL_MODE,
  220. PROTOCOL_OPTIONS,
  221. STATUS_POLL_MAX_INTERVAL,
  222. STATUS_POLL_MIN_INTERVAL,
  223. getModbusSlaveAddress,
  224. getState,
  225. init,
  226. isModbusProtocol,
  227. isStorageAccessProtocol,
  228. setModbusSlaveAddress,
  229. setNightModeEnabled,
  230. setNightModeFollowSystem,
  231. setParameterAutoPollEnabled,
  232. setParameterMaxPacketLength,
  233. setParameterPollInterval,
  234. setProtocolMode,
  235. subscribe
  236. }