initialize
This commit is contained in:
157
eg4battery/Install.md
Normal file
157
eg4battery/Install.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# EG4 LifePower4 v2 → HA Monitoring Install
|
||||
|
||||
Target: Debian-family Linux (developed on Raspberry Pi CM5), one USB-to-RS-485
|
||||
adapter per pack's **RS485** socket, HA MQTT broker on the LAN.
|
||||
|
||||
> **Shortcut:** [`install.sh`](./install.sh) automates §3–§7 and supports
|
||||
> `--dry-run` for a no-hardware smoke test. This doc explains what it does
|
||||
> and how to do it by hand.
|
||||
|
||||
Path conventions: `$BASE` = root of this package (e.g. `~/solar/eg4battery`).
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
- `uv` on `$PATH` ([docs](https://docs.astral.sh/uv/))
|
||||
- `sudo`
|
||||
- **One USB-to-RS-485 adapter per pack**. FTDI-based is what we've tested
|
||||
(FT232R + MAX485 combo, identified by the Linux kernel as `FT232R USB UART`
|
||||
with a unique serial-number suffix). CH340 / CP210x also fine — adjust
|
||||
the udev rule's vendor/product ID.
|
||||
|
||||
## 2. Cabling — read this before wiring
|
||||
|
||||
LP4V2 back panel has four RJ45 sockets: `CAN`, `RS485`, `Comm1`, `Comm2`.
|
||||
Only `RS485` is relevant for our daemon:
|
||||
|
||||
| Socket | Use for monitoring? |
|
||||
|--------|---------------------------------------------------------------------|
|
||||
| CAN | No — separate bus, CAN signaling, for inverter BMS comms |
|
||||
| RS485 | **Yes.** External monitor port. Pin 1-2 = B/A. Modbus RTU at 9600. |
|
||||
| Comm1 | No — inter-pack hub bus (19200 Modbus). Leave for pack daisy-chain. |
|
||||
| Comm2 | No — same internal bus as Comm1. |
|
||||
|
||||
The stock EG4 USB-RS-485 cable (included with each pack) is already wired
|
||||
correctly for the RS485 socket (pins 1-2 / A-B).
|
||||
|
||||
**Topology**: each pack gets its own adapter plugged into its **RS485** socket.
|
||||
No daisy chain required for monitoring — each pack is a dedicated bus. The
|
||||
Comm1↔Comm2 daisy chain between packs is separate and carries the inter-pack
|
||||
hub bus (not our concern).
|
||||
|
||||
## 3. udev rule
|
||||
|
||||
Grants `dialout` group access to FTDI USB-serial adapters.
|
||||
|
||||
```bash
|
||||
sudo install -m 644 "$BASE/etc/udev/rules.d/99-eg4-rs485.rules" \
|
||||
/etc/udev/rules.d/99-eg4-rs485.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --subsystem-match=tty
|
||||
ls -l /dev/serial/by-id/ # expect one symlink per adapter
|
||||
```
|
||||
|
||||
## 4. Daemon binary
|
||||
|
||||
```bash
|
||||
sudo install -m 755 "$BASE/bin/eg4-battery" /usr/local/bin/eg4-battery
|
||||
```
|
||||
|
||||
uv handles deps; no venv work on your side.
|
||||
|
||||
## 5. Config
|
||||
|
||||
Canonical template: [`config/eg4-battery.yaml.example`](./config/eg4-battery.yaml.example).
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/eg4-battery
|
||||
install -m 600 "$BASE/config/eg4-battery.yaml.example" \
|
||||
~/.config/eg4-battery/eg4-battery.yaml
|
||||
# Edit — see "mode selection" below
|
||||
```
|
||||
|
||||
### 5a. mode selection
|
||||
|
||||
- **`modbus_per_pack`** (default / recommended). Each pack listed with its own
|
||||
`port:`, `address:` and `baud:` — the daemon opens one serial port per pack
|
||||
and polls each independently.
|
||||
```yaml
|
||||
bus:
|
||||
mode: modbus_per_pack
|
||||
timeout_s: 1.0
|
||||
poll_interval_s: 10.0
|
||||
packs:
|
||||
- name: lifepower4_1
|
||||
address: 0x40
|
||||
port: /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_<ID1>-if00-port0
|
||||
baud: 9600
|
||||
- name: lifepower4_2
|
||||
address: 0x40
|
||||
port: /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_<ID2>-if00-port0
|
||||
baud: 9600
|
||||
```
|
||||
|
||||
- **`active`** (legacy, V1 hardware only) — single shared bus, EG4 7E/0D
|
||||
protocol at 9600. Not used on V2 Auto-Addressing hardware.
|
||||
|
||||
- **`passive`** (diagnostic) — listen-only Modbus sniff at 19200. See
|
||||
[`NOTES.md`](./NOTES.md) "Modes" for details.
|
||||
|
||||
### 5b. MQTT creds
|
||||
|
||||
Replace `<MQTT_BROKER_IP>`, `<MQTT_USER>`, `<MQTT_PASSWORD>`. `install.sh`
|
||||
will not auto-start the service while those placeholders remain.
|
||||
|
||||
## 6. Smoke test without hardware
|
||||
|
||||
```bash
|
||||
eg4-battery -C ~/.config/eg4-battery/eg4-battery.yaml --dry-run
|
||||
```
|
||||
|
||||
Mock transport, one cycle per pack, prints every discovery-config and
|
||||
state-topic / payload to stdout. Confirms the pipeline end-to-end before
|
||||
hardware is involved.
|
||||
|
||||
## 7. systemd
|
||||
|
||||
```bash
|
||||
sudo install -m 644 "$BASE/etc/systemd/system/eg4-battery.service" \
|
||||
/etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now eg4-battery.service
|
||||
journalctl -u eg4-battery.service -f
|
||||
```
|
||||
|
||||
Service includes `Environment=PATH=…` so uv is found under systemd.
|
||||
|
||||
## 8. Bring up additional packs
|
||||
|
||||
When a new pack comes online:
|
||||
|
||||
1. Plug its adapter into the pack's **RS485** socket and power the pack.
|
||||
2. `ls -l /dev/serial/by-id/` — note the new symlink.
|
||||
3. Add / update an entry in `~/.config/eg4-battery/eg4-battery.yaml`:
|
||||
```yaml
|
||||
- name: lifepower4_N
|
||||
address: 0x40
|
||||
port: /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_<ID>-if00-port0
|
||||
baud: 9600
|
||||
```
|
||||
4. `sudo systemctl restart eg4-battery.service`. The journal shows
|
||||
`pack lifepower4_N: recovered after N failed cycle(s)` within ~10 s when
|
||||
the pack starts responding, and HA auto-discovers ~65 entities.
|
||||
|
||||
## 9. Verify MQTT flow
|
||||
|
||||
```bash
|
||||
# modbus_per_pack: all named + raw register entities per pack
|
||||
mosquitto_sub -h <broker> -u mqtt -P <pass> \
|
||||
-t 'homeassistant/sensor/lifepower4_+_pack_voltage/state' \
|
||||
-t 'homeassistant/sensor/lifepower4_+_soc/state' \
|
||||
-t 'homeassistant/sensor/lifepower4_+_cell_voltage_delta_mv/state' \
|
||||
-v
|
||||
```
|
||||
|
||||
## 10. Swapping modes later
|
||||
|
||||
Change `bus.mode` in the config, restart the service. Config reshape varies
|
||||
per mode — see §5a. No binary redeploy needed.
|
||||
160
eg4battery/NOTES.md
Normal file
160
eg4battery/NOTES.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# EG4 LifePower4 v2 — architecture & protocol notes
|
||||
|
||||
## Modes — choose per deployment
|
||||
|
||||
`bus.mode` in the config picks one of three daemon modes:
|
||||
|
||||
| Mode | Wire protocol | Baud | Role | Status |
|
||||
|------------------|----------------------|-------|----------------|------------------------------------------------------------|
|
||||
| `modbus_per_pack`| Modbus RTU, fn 0x03 | 9600 | master (per pack)| **Primary path for LP4V2 Auto-Addressing.** One FTDI per pack's RS485 port, polls once per cycle, fully decodes into named HA entities. |
|
||||
| `active` | EG4 7E/0D legacy | 9600 | master (shared) | **Legacy.** V1 firmware only. V2 packs don't respond to this protocol — kept for reference. |
|
||||
| `passive` | Modbus RTU sniff | 19200 | listener | **Diagnostic.** Originally intended to listen on an LVX6048 BMS bus; the LVX6048 doesn't poll EG4 packs that way, so has no production use here. |
|
||||
|
||||
## How we got here (summary)
|
||||
|
||||
1. **Port matrix test** (2026-04-24). Established that the LP4V2 back panel's four RJ45s (CAN / RS485 / Comm1 / Comm2) carry three distinct electrical buses:
|
||||
- Comm1 + Comm2 = inter-pack hub bus (19200 Modbus, master-to-slave coordination). Pin 1-2 and pin 7-8 both tap the same bus.
|
||||
- RS485 = external monitor bus. Inactive until an external master drives it.
|
||||
- CAN = separate bus, not in scope.
|
||||
2. **EG4 BMS Tool capture.** User confirmed the stock Windows/macOS BMS Tool connects to the RS485 port at 9600 baud, Modbus slave ID **0x40**. Our first canonical Modbus probe at that address returned a clean 99-byte reply.
|
||||
3. **`lv_host.app` reverse-engineering.** The BMS Tool is a Qt app. Its Mach-O binary contains:
|
||||
- SQLite schema for the `total` table → complete list of 39 fields the BMS Tool stores per cycle.
|
||||
- String-table names for warning / protection bit flags.
|
||||
- C++ symbols `BmsDatalog::allFunctionModbusAnalysis`, `BmsMonitoring::allFunctionModbusAnalysis`, `usModbusAskRegBase` etc. → confirms Modbus RTU fn 0x03 read-holding-regs.
|
||||
4. **Register map construction.** Correlated live register values (cell voltages, pack V) against the SQL field list to derive the 47-reg map below. High-confidence fields promoted to named HA entities; unknowns still emitted as `register_NN` for future correlation.
|
||||
|
||||
## Register map (Modbus fn 0x03, start 0x0000, count 47)
|
||||
|
||||
From live observation + lv_host.app schema:
|
||||
|
||||
| Reg | Observed | Field | Scale | Unit | HA entity suffix |
|
||||
|-------|--------------|---------------------|---------|------|----------------------|
|
||||
| 00 | 5256 | Total_Voltage | × 0.01 | V | `pack_voltage` |
|
||||
| 01 | 0 (signed) | Current_I | × 0.01 | A | `pack_current` |
|
||||
| 02-17 | ~3285 each | Vol_Cell01..16 | × 0.001 | V | `cell_01_voltage`..`cell_16_voltage` + `cell_voltage_min/max/delta_mv/lowest/highest` |
|
||||
| 18 | 21 | Temp_01 | × 1 | °C | `temperature_01` |
|
||||
| 19 | 21 | Temp_02 | × 1 | °C | `temperature_02` |
|
||||
| 20 | 20 | Temp_03 | × 1 | °C | `temperature_03` |
|
||||
| 21 | 54 | Temp_04 | × 1 | °C | `temperature_04` |
|
||||
| 22 | 100 | SOC | × 1 | % | `soc` |
|
||||
| 23 | 100 | SOH | × 1 | % | `soh` |
|
||||
| 24 | 55 | Temp_PCB | × 1 | °C | `temperature_pcb` |
|
||||
| 25-29 | 0 | reserved | | | (register_NN only) |
|
||||
| 30 | 1 | Heater (bit 0) | | | `heater` (on/off) |
|
||||
| 31 | 5493 | MAX_Curren | × 0.01 | A | `max_current_limit` |
|
||||
| 32 | 10752 | *?* | | | (register_32) |
|
||||
| 33 | ? | Warning bitfield | | | `warning_*` (14 bits)|
|
||||
| 34 | ? | Protection bitfield | | | `protection_*` (14 bits)|
|
||||
| 35 | 0 | Error_Code | | | `error_code` |
|
||||
| 36 | 16 | Cell_Num | | | `cell_count` |
|
||||
| 37 | 1000 | Capacity | × 0.1 | Ah | `capacity_ah` |
|
||||
| 38 | 0 | Remaining | × 0.01 | Ah | `remaining_ah` |
|
||||
| 39 | 0 | CycleNum | | | `cycle_count` |
|
||||
| 40 | 7 | Battery_Mode (enum) | | | `battery_mode` |
|
||||
| 41 | 0x0fff | BMS_Version (hi) | | | `bms_version_hi` |
|
||||
| 42 | 0x07ff | BMS_Version (lo) | | | `bms_version_lo` |
|
||||
| 43-45 | — | *?* | | | (register_NN only) |
|
||||
| 46 | +1.25 Hz | runtime counter | × 0.1 s?| | `uptime_ds` |
|
||||
|
||||
**Confidence levels**: Bold-worthy certain (confirmed by live values + UI labels): pack_voltage, cells 01-16, SOC, SOH, cell_count, capacity_ah. Medium (fits data, unverified): temps, current, bitfields, Battery_Mode. Unknown: regs 32, 35 (probably Error_Code but value always 0 so far), 38-40, 43-45.
|
||||
|
||||
## Warning / protection bit maps
|
||||
|
||||
From the UI labels in lv_host.app (bit 0 = first listed):
|
||||
|
||||
| Bit | Warning (reg 33) | Protection (reg 34) |
|
||||
|-----|-------------------|---------------------|
|
||||
| 0 | pack_ov | pack_ov |
|
||||
| 1 | cell_ov | cell_ov |
|
||||
| 2 | pack_uv | pack_uv |
|
||||
| 3 | cell_uv | cell_uv |
|
||||
| 4 | charge_oc | charge_oc |
|
||||
| 5 | discharge_oc | discharge_oc |
|
||||
| 6 | temp_anomaly | temp_anomaly |
|
||||
| 7 | mos_ot | mos_ot |
|
||||
| 8 | charge_ot | charge_ot |
|
||||
| 9 | discharge_ot | discharge_ot |
|
||||
| 10 | charge_ut | charge_ut |
|
||||
| 11 | discharge_ut | discharge_ut |
|
||||
| 12 | low_capacity | float_stopped |
|
||||
| 13 | other_error | discharge_sc |
|
||||
|
||||
Each bit becomes an HA sensor reporting `on` / `off`. Exact bit ordering is guessed from UI display order — adjust if the EG4 tool ever shows a flag we don't match.
|
||||
|
||||
## Hardware topology notes
|
||||
|
||||
### Critical: RS485 port only works when the pack is standalone
|
||||
|
||||
**Empirical finding** (2026-04-24): the LP4V2's external `RS485` port
|
||||
only answers Modbus queries when the pack is **not** daisy-chained to
|
||||
other packs via `Comm1`/`Comm2`. Specifically:
|
||||
|
||||
- With daisy chains intact (bat1 Comm2 → bat2 Comm1 etc.), one pack
|
||||
elects as master and polls slaves over the internal hub bus
|
||||
(19200 Modbus on Comm1/Comm2). Slave packs' RS485 ports go silent —
|
||||
only the master responds externally.
|
||||
- Remove the inter-pack Comm jumpers and each pack becomes a
|
||||
self-contained master: its Comm1/Comm2 LEDs flash (it's trying to
|
||||
poll slaves that aren't there), and its own RS485 port becomes fully
|
||||
live for external queries.
|
||||
|
||||
**Implication**: `modbus_per_pack` mode requires **each pack standalone**
|
||||
— one FTDI adapter per pack's RS485 port, no inter-pack Comm jumpers.
|
||||
This is how we got bat1 responding cleanly. If the batteries later
|
||||
need to be daisy-chained to an inverter, only the master pack's RS485
|
||||
port will answer external queries; slave per-pack data would need to
|
||||
come from decoding the Comm1/Comm2 hub bus instead (a future mode).
|
||||
|
||||
### Port roles on the LP4V2 pack (from the port matrix test)
|
||||
|
||||
| Port | Role | Pins carrying signal | Protocol / baud |
|
||||
|-------|--------------------------------|-------------------------|-----------------------|
|
||||
| CAN | Inverter CAN comms | (CAN-specific pinout) | CANbus (not RS-485) |
|
||||
| RS485 | External monitor | 1-2 | Modbus RTU @ 9600 |
|
||||
| Comm1 | Inter-pack hub bus (in/out) | 1-2 and 7-8 both tap it | Modbus RTU @ 19200 |
|
||||
| Comm2 | Inter-pack hub bus (in/out) | 1-2 and 7-8 both tap it | Modbus RTU @ 19200 |
|
||||
|
||||
- The **stock USB-RS485 cable** ships wired to pins 1-2 — usable on either Comm or RS485.
|
||||
- The **pin 7-8 modified cable** only gains us the Comm/Comm2 hub-bus tap; since pins 1-2 reach the same bus, it's not strictly necessary. Kept in the toolkit for diagnostic purposes.
|
||||
- Factory inter-pack jumpers (between packs) are 8-conductor CAT5 — they carry both pin pairs.
|
||||
|
||||
### Adapters
|
||||
|
||||
On this host, three USB-FTDI adapters are plugged into the three packs' RS485 ports:
|
||||
|
||||
| Adapter ID | Pack | `/dev/serial/by-id/...` |
|
||||
|------------------|----------------|--------------------------------------------------------|
|
||||
| A994XMVK | bat1 (RS485) | `usb-FTDI_FT232R_USB_UART_A994XMVK-if00-port0` |
|
||||
| A994XGUY | bat2 (RS485) | `usb-FTDI_FT232R_USB_UART_A994XGUY-if00-port0` |
|
||||
| A994XMBR | bat3 (RS485) | `usb-FTDI_FT232R_USB_UART_A994XMBR-if00-port0` |
|
||||
|
||||
Each pack gets polled on its own bus → no shared-bus arbitration, no master/slave coordination needed, pack Modbus address is 0x40 for all of them.
|
||||
|
||||
## LVX6048 compatibility (still true)
|
||||
|
||||
LVX6048 BMS port protocols: `PYL` (Pylontech), `LIb` (MPP LIO), `WEC` (WECO), `SOL` (Soltaro), `VSC` (Pylontech-CAN), `USE` (voltage-only). **No native EG4 LP4V2 support.** For inverter↔battery comms, set `P05/P14 = USE` and manage charge profile via `lvx-flash`. See DIY Solar Forum threads 67496 & 96019, LVX6048WP manual §9-2.
|
||||
|
||||
## Bring-up checklist (when a new pack goes live)
|
||||
|
||||
1. Wire: plug USB-FTDI adapter (stock pin-1-2 cable) into the pack's **RS485** port.
|
||||
2. Confirm the pack's BMS is powered (LEDs steady on Comm1 + Comm2, not dark).
|
||||
3. Verify the `/dev/serial/by-id/...` symlink exists for the adapter.
|
||||
4. Add a pack entry to the config:
|
||||
```yaml
|
||||
packs:
|
||||
- name: lifepower4_N
|
||||
address: 0x40
|
||||
port: /dev/serial/by-id/usb-FTDI_...-if00-port0
|
||||
baud: 9600
|
||||
```
|
||||
5. `sudo systemctl restart eg4-battery.service`. Watch journal — within ~10 s you should see the first MQTT publish, or `WARNING: no/bad response` if the pack isn't answering.
|
||||
6. In HA: `EG4 LifePower4 lifepower4_N` device appears with ~65 auto-discovered entities.
|
||||
|
||||
## Sources / references
|
||||
|
||||
- `lv_host.app` (Qt) — Contents/MacOS/lv_host Mach-O binary + my1.db/my2.db SQLite schemas
|
||||
- `../battery/eg4_lifepower.py` — V1 7E/0D decoder (Louisvdw/dbus-serialbattery port), historical reference
|
||||
- `../battery/sweep.py` — protocol + baud scanner used for initial triage
|
||||
- EG4 "Cables Needed for Updating" PDF
|
||||
- EG4 Community Forum: "Specs for LifePower4 V2 BAT-COM ports"
|
||||
- LVX6048WP manual §9-2 (BMS pinout), §Programs P03/P05
|
||||
95
eg4battery/README.md
Normal file
95
eg4battery/README.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# EG4 LifePower4 v2 → Home Assistant
|
||||
|
||||
Daemon that polls EG4 LifePower4 48V 100Ah v2 (Auto-Addressing) packs over
|
||||
RS-485 and publishes per-pack telemetry to MQTT with HA auto-discovery.
|
||||
|
||||
## Status: live
|
||||
|
||||
As of 2026-04-24, `bat1` is live via `modbus_per_pack` mode on its RS485 port,
|
||||
reporting all ~65 entities into HA:
|
||||
|
||||
```
|
||||
lifepower4_1_pack_voltage 52.56 V (16 cells × 3.285 V)
|
||||
lifepower4_1_cell_01_voltage 3.285 V
|
||||
lifepower4_1_cell_16_voltage 3.285 V
|
||||
lifepower4_1_cell_voltage_delta_mv 2 (outstanding balance)
|
||||
lifepower4_1_soc 100 %
|
||||
lifepower4_1_capacity_ah 100.0 Ah
|
||||
lifepower4_1_temperature_01 21 °C
|
||||
lifepower4_1_temperature_pcb 55 °C
|
||||
... plus 14 warning bits, 14 protection bits, all 47 raw registers
|
||||
```
|
||||
|
||||
`bat2` and `bat3` are wired but unpowered — the daemon logs one warning per
|
||||
unreachable pack per startup and keeps retrying silently. They'll come online
|
||||
automatically when the user powers them up.
|
||||
|
||||
## Modes
|
||||
|
||||
Set by `bus.mode` in `~/.config/eg4-battery/eg4-battery.yaml`:
|
||||
|
||||
| Mode | When to use |
|
||||
|-------------------|---------------------------------------------------------|
|
||||
| `modbus_per_pack` | **Default.** One FTDI per pack's RS485 port. Fully decoded HA entities. |
|
||||
| `active` | Legacy 7E/0D (V1 firmware only). Not used on V2 hardware. |
|
||||
| `passive` | Listen-only Modbus sniff (19200). Diagnostic use. |
|
||||
|
||||
See [`NOTES.md`](./NOTES.md) for architecture, register map, LVX6048
|
||||
compatibility findings, and bring-up checklist.
|
||||
|
||||
## What's in the box
|
||||
|
||||
```
|
||||
eg4battery/
|
||||
├── README.md ← start here
|
||||
├── Install.md ← detailed walkthrough + mode-switch howto
|
||||
├── NOTES.md ← architecture, register map, port matrix
|
||||
├── install.sh ← idempotent installer (supports --dry-run)
|
||||
│
|
||||
├── bin/eg4-battery ← single-file daemon (uv PEP-723 inline deps)
|
||||
│
|
||||
├── config/eg4-battery.yaml.example ← template, multiple-pack config
|
||||
│
|
||||
├── etc/ mirror of target paths (Pi side)
|
||||
│ ├── udev/rules.d/99-eg4-rs485.rules
|
||||
│ └── systemd/system/eg4-battery.service
|
||||
│
|
||||
├── homeassistant/ ← drop into your HA config dir
|
||||
│ ├── README.md (what goes where + retention tiers)
|
||||
│ ├── recorder.yaml (exclude noisy / diagnostic entities)
|
||||
│ ├── template_sensors.yaml (derived: power, temp_max, cell_imbalance, stack rollups)
|
||||
│ └── lovelace_overview.yaml (3-pack stack dashboard)
|
||||
│
|
||||
└── tmp/ ad-hoc diagnostics
|
||||
├── port-probe (single-cycle 9600/19200/7E probe)
|
||||
├── eg4-snapshot (47-reg dump for BMS Tool cross-check)
|
||||
└── bms-tool-ref/ (unpacked vendor BMS Tool for RE reference)
|
||||
```
|
||||
|
||||
## Quick start on a fresh host
|
||||
|
||||
```bash
|
||||
cd ~/solar/eg4battery
|
||||
./install.sh --dry-run # mock cycle, prints MQTT payloads, exits
|
||||
|
||||
# Edit ~/.config/eg4-battery/eg4-battery.yaml:
|
||||
# - For modbus_per_pack: one 'packs:' entry per pack, each with port + address + baud
|
||||
# - mqtt.host / username / password
|
||||
|
||||
./install.sh # real deploy; auto-starts once creds are filled
|
||||
journalctl -u eg4-battery.service -f
|
||||
```
|
||||
|
||||
## Related packages
|
||||
|
||||
- [`../LVX6048/`](../LVX6048/) — inverter-side monitoring via PI18 over USB-HID.
|
||||
Same MQTT broker. Between the two packages, HA sees every useful number from
|
||||
the stack.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
- `battery/eg4_lifepower.py` — V1 protocol decoder adapted from
|
||||
[`Louisvdw/dbus-serialbattery`](https://github.com/Louisvdw/dbus-serialbattery).
|
||||
Historical; V2 firmware moved to Modbus on a different port.
|
||||
- EG4 Electronics `lv_host.app` — the vendor BMS Tool; its Qt binary's SQLite
|
||||
schema and strings gave us the register-to-field mapping.
|
||||
969
eg4battery/bin/eg4-battery
Executable file
969
eg4battery/bin/eg4-battery
Executable file
@@ -0,0 +1,969 @@
|
||||
#!/usr/bin/env -S uv run --script
|
||||
# /// script
|
||||
# requires-python = ">=3.11"
|
||||
# dependencies = [
|
||||
# "pyserial>=3.5",
|
||||
# "paho-mqtt>=2.0",
|
||||
# "pyyaml>=6.0",
|
||||
# ]
|
||||
# ///
|
||||
"""
|
||||
eg4-battery — telemetry bridge from EG4 LifePower4 v2 BMSes to MQTT/HA.
|
||||
|
||||
Three modes, selected via `bus.mode` in the config:
|
||||
|
||||
modbus_per_pack — RECOMMENDED. One FTDI RS-485 adapter per pack. Each pack
|
||||
has its own (port, address, baud) in the `packs:` list.
|
||||
Uses Modbus RTU fn=0x03 read-47-regs at 0x0000. Decoder
|
||||
extracts named fields (pack V, 16 cell voltages, temps,
|
||||
SoC, SoH, Capacity, warnings, protections) — register
|
||||
map reverse-engineered from the EG4 `lv_host.app` BMS
|
||||
Tool's SQLite schema + UI labels.
|
||||
|
||||
active — LEGACY. Single FTDI adapter on a dedicated bus, EG4
|
||||
7E/0D protocol at 9600 baud. Was ported from the V1
|
||||
firmware via `battery/eg4_lifepower.py`; V2 hardware
|
||||
doesn't speak this protocol in practice. Kept for
|
||||
reference / possible V1 deployments.
|
||||
|
||||
passive — LEGACY. Listen-only Modbus-RTU sniffer at 19200 baud.
|
||||
Originally targeted the LVX6048 BMS bus; LVX6048 doesn't
|
||||
poll EG4 packs that way, so the mode is diagnostic only.
|
||||
|
||||
Usage:
|
||||
eg4-battery -C <config.yaml>
|
||||
eg4-battery -C <config.yaml> --dry-run # mock bus, print, exit
|
||||
eg4-battery -C <config.yaml> --trace # log every frame
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import dataclasses
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
import struct
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
from struct import unpack_from
|
||||
from typing import Any, Iterator
|
||||
|
||||
import paho.mqtt.client as mqtt
|
||||
import serial
|
||||
import yaml
|
||||
|
||||
log = logging.getLogger("eg4-battery")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# === config ==================================================================
|
||||
# =============================================================================
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class PackConfig:
|
||||
name: str # HA entity prefix / device identifier (e.g. "lifepower4_1")
|
||||
address: int # protocol-level address (Modbus slave ID, or EG4 7E address)
|
||||
port: str | None = None # per-pack port (modbus_per_pack mode only)
|
||||
baud: int | None = None # per-pack baud override (modbus_per_pack mode only)
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class BusConfig:
|
||||
mode: str # "modbus_per_pack" | "active" | "passive"
|
||||
transport: str = "serial" # "serial" | "mock"
|
||||
port: str = "" # shared port (active / passive modes)
|
||||
baud: int = 9600
|
||||
read_chunk: int = 512
|
||||
timeout_s: float = 1.5 # per-query timeout
|
||||
poll_interval_s: float = 10.0 # full round-robin cycle target
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class MQTTConfig:
|
||||
host: str
|
||||
port: int
|
||||
username: str
|
||||
password: str
|
||||
discovery_prefix: str = "homeassistant"
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class AppConfig:
|
||||
bus: BusConfig
|
||||
mqtt: MQTTConfig
|
||||
packs: list[PackConfig]
|
||||
cell_count: int = 16 # active mode only
|
||||
|
||||
|
||||
def load_config(path: Path) -> AppConfig:
|
||||
raw = yaml.safe_load(path.read_text())
|
||||
return AppConfig(
|
||||
bus=BusConfig(**raw["bus"]),
|
||||
mqtt=MQTTConfig(**raw["mqtt"]),
|
||||
packs=[PackConfig(**p) for p in raw["packs"]],
|
||||
cell_count=raw.get("cell_count", 16),
|
||||
)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# === active mode: EG4 7E/0D protocol =========================================
|
||||
# =============================================================================
|
||||
# Verified against `battery/eg4_lifepower.py`. Frame:
|
||||
# request (6 bytes): 7E <addr> <cmd> 00 <chk> 0D
|
||||
# chk = (0x100 - (addr + cmd + len)) & 0xFF
|
||||
# reply (variable): 7E <addr> <cmd> <len> [10 groups] <chk> 0D
|
||||
# each group: <type_byte> <count> <count × big-endian uint16>
|
||||
|
||||
|
||||
CMD_GENERAL_STATUS = 0x01 # cells, V, I, SoC, cap, temps, cycles, alarms
|
||||
CMD_FW_VER = 0x33
|
||||
CMD_HW_VER = 0x42
|
||||
|
||||
|
||||
def encode_eg4_request(address: int, cmd: int, length: int = 0) -> bytes:
|
||||
chk = (0x100 - (address + cmd + length)) & 0xFF
|
||||
return bytes([0x7E, address, cmd, length, chk, 0x0D])
|
||||
|
||||
|
||||
def decode_eg4_general_status(data: bytes, cell_count: int) -> dict[str, Any]:
|
||||
"""Decode a fn=0x01 reply into a flat dict keyed for HA. Mirrors
|
||||
`battery/eg4_lifepower.py::parse_status`. Permissive framing check
|
||||
(header/footer); upstream doesn't validate the reply CRC and neither
|
||||
do we until we know the algorithm."""
|
||||
if not data or len(data) < 6 or data[0] != 0x7E or data[-1] != 0x0D:
|
||||
raise ValueError(f"bad framing: {data.hex(' ')[:120]}")
|
||||
|
||||
groups: list[list[int]] = []
|
||||
i = 4 # skip 7E <addr> <cmd> <len>
|
||||
for _ in range(10):
|
||||
if i + 2 > len(data):
|
||||
raise ValueError(f"truncated payload at group {len(groups)}")
|
||||
group_len = data[i + 1]
|
||||
end = i + 2 + group_len * 2
|
||||
if end > len(data):
|
||||
raise ValueError(f"group {len(groups)} overruns frame (end={end}, len={len(data)})")
|
||||
payload = data[i + 2:end]
|
||||
groups.append([unpack_from(">H", payload, k)[0] for k in range(0, len(payload), 2)])
|
||||
i = end
|
||||
|
||||
out: dict[str, Any] = {}
|
||||
|
||||
# group 0 — cell voltages (mV; mask 0x7FFF per upstream — top bit is some flag)
|
||||
cells = [(v & 0x7FFF) / 1000.0 for v in groups[0][:cell_count]]
|
||||
for idx, cv in enumerate(cells, start=1):
|
||||
out[f"cell_{idx:02d}_voltage"] = round(cv, 3)
|
||||
if cells:
|
||||
vmin, vmax = min(cells), max(cells)
|
||||
out["cell_voltage_min"] = round(vmin, 3)
|
||||
out["cell_voltage_max"] = round(vmax, 3)
|
||||
out["cell_voltage_delta_mv"] = round((vmax - vmin) * 1000)
|
||||
out["cell_lowest"] = cells.index(vmin) + 1
|
||||
out["cell_highest"] = cells.index(vmax) + 1
|
||||
|
||||
# group 1 — current (signed; encoded as 30000 - A×100; positive = charge)
|
||||
if groups[1]:
|
||||
out["current"] = round((30000 - groups[1][0]) / 100.0, 2)
|
||||
# group 2 — SoC × 100
|
||||
if groups[2]:
|
||||
out["soc"] = round(groups[2][0] / 100.0, 1)
|
||||
# group 3 — capacity (Ah × 100)
|
||||
if groups[3]:
|
||||
out["capacity_ah"] = round(groups[3][0] / 100.0, 2)
|
||||
# group 4 — temperatures (low byte − 50 °C)
|
||||
for idx, raw in enumerate(groups[4][:6], start=1):
|
||||
out[f"temperature_{idx}"] = (raw & 0xFF) - 50
|
||||
# group 5 — alarm bitfield (second word per upstream)
|
||||
flags = groups[5][1] if len(groups[5]) > 1 else 0
|
||||
out["alarm_current_over"] = "on" if flags & 0b00001000 else "off"
|
||||
out["alarm_voltage_high"] = "on" if flags & 0b00010000 else "off"
|
||||
out["alarm_voltage_low"] = "on" if flags & 0b00100000 else "off"
|
||||
out["alarm_temp_high_chg"] = "on" if flags & 0b01000000 else "off"
|
||||
out["alarm_temp_low_chg"] = "on" if flags & 0b10000000 else "off"
|
||||
# group 6 — cycle count
|
||||
if groups[6]:
|
||||
out["cycle_count"] = groups[6][0]
|
||||
# group 7 — pack voltage (V × 100)
|
||||
if groups[7]:
|
||||
out["pack_voltage"] = round(groups[7][0] / 100.0, 2)
|
||||
# groups 8-9 — undecoded; leave as future work
|
||||
return out
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# === passive mode: Modbus RTU framing ========================================
|
||||
# =============================================================================
|
||||
|
||||
|
||||
def crc16_modbus(data: bytes) -> int:
|
||||
crc = 0xFFFF
|
||||
for b in data:
|
||||
crc ^= b
|
||||
for _ in range(8):
|
||||
if crc & 1:
|
||||
crc = (crc >> 1) ^ 0xA001
|
||||
else:
|
||||
crc >>= 1
|
||||
return crc
|
||||
|
||||
|
||||
def _crc_ok(buf: bytes, start: int, length: int) -> bool:
|
||||
if start + length > len(buf):
|
||||
return False
|
||||
body = buf[start:start + length - 2]
|
||||
expected = buf[start + length - 2] | (buf[start + length - 1] << 8)
|
||||
return crc16_modbus(body) == expected
|
||||
|
||||
|
||||
_MODBUS_FUNCS = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0F, 0x10, 0x16, 0x17}
|
||||
|
||||
|
||||
def parse_modbus_frame_at(buf: bytes, start: int) -> tuple[int, str] | None:
|
||||
if start + 4 > len(buf):
|
||||
return None
|
||||
func = buf[start + 1]
|
||||
# exception response (5 bytes), only for legitimate function codes
|
||||
if func >= 0x80 and (func & 0x7F) in _MODBUS_FUNCS \
|
||||
and start + 5 <= len(buf) and 1 <= buf[start + 2] <= 11 \
|
||||
and _crc_ok(buf, start, 5):
|
||||
return (5, "exception")
|
||||
if func == 0x03:
|
||||
# query: 8 bytes
|
||||
if _crc_ok(buf, start, 8):
|
||||
return (8, "query")
|
||||
# response: 1 + 1 + 1 + byte_count + 2
|
||||
if start + 3 <= len(buf):
|
||||
byte_count = buf[start + 2]
|
||||
if 2 <= byte_count <= 250 and byte_count % 2 == 0:
|
||||
total = 3 + byte_count + 2
|
||||
if _crc_ok(buf, start, total):
|
||||
return (total, "response")
|
||||
return None
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class ModbusFrame:
|
||||
address: int
|
||||
function: int
|
||||
kind: str
|
||||
raw: bytes
|
||||
|
||||
@property
|
||||
def registers(self) -> list[int]:
|
||||
if self.kind != "response" or self.function != 0x03:
|
||||
return []
|
||||
bc = self.raw[2]
|
||||
d = self.raw[3:3 + bc]
|
||||
return [(d[i] << 8) | d[i + 1] for i in range(0, len(d), 2)]
|
||||
|
||||
|
||||
def decode_modbus_response(frame: ModbusFrame) -> dict[str, Any]:
|
||||
"""Raw-register dump; promote to named fields once we know the layout."""
|
||||
return {f"register_{i:02d}": v for i, v in enumerate(frame.registers)}
|
||||
|
||||
|
||||
# ---- modbus_per_pack active-poll decoder (EG4 LP4V2) -----------------------
|
||||
# Register map derived from lv_host.app BMS Tool SQLite schema + UI labels +
|
||||
# live probing of a single pack. See ../NOTES.md "Register map" section.
|
||||
# High-confidence fields promoted to named entities; unknowns (reg 32, 35,
|
||||
# 38-40, 43-45) still emitted as register_NN for correlation.
|
||||
|
||||
_WARNING_BITS = [
|
||||
"pack_ov", "cell_ov", "pack_uv", "cell_uv",
|
||||
"charge_oc", "discharge_oc", "temp_anomaly", "mos_ot",
|
||||
"charge_ot", "discharge_ot", "charge_ut", "discharge_ut",
|
||||
"low_capacity", "other_error",
|
||||
]
|
||||
_PROTECTION_BITS = [
|
||||
"pack_ov", "cell_ov", "pack_uv", "cell_uv",
|
||||
"charge_oc", "discharge_oc", "temp_anomaly", "mos_ot",
|
||||
"charge_ot", "discharge_ot", "charge_ut", "discharge_ut",
|
||||
"float_stopped", "discharge_sc",
|
||||
]
|
||||
|
||||
|
||||
def _signed16(v: int) -> int:
|
||||
return v - 0x10000 if v & 0x8000 else v
|
||||
|
||||
|
||||
def decode_eg4_modbus_regs(regs: list[int]) -> dict[str, Any]:
|
||||
"""Decode the 47-reg read-holding-regs response from an LP4V2 BMS.
|
||||
Emits named HA entities where meaning is known; raw register_NN
|
||||
passthrough for the rest."""
|
||||
out: dict[str, Any] = {}
|
||||
# always emit raw registers — invaluable for future refinement
|
||||
for i, v in enumerate(regs):
|
||||
out[f"register_{i:02d}"] = v
|
||||
|
||||
if len(regs) < 47:
|
||||
return out
|
||||
|
||||
# --- pack-level V / I (regs 0, 1) ---
|
||||
out["pack_voltage"] = round(regs[0] / 100.0, 2)
|
||||
out["pack_current"] = round(_signed16(regs[1]) / 100.0, 2)
|
||||
|
||||
# --- 16 cell voltages (regs 2-17), mV ---
|
||||
cells_v = [regs[2 + i] / 1000.0 for i in range(16)]
|
||||
for i, cv in enumerate(cells_v, start=1):
|
||||
out[f"cell_{i:02d}_voltage"] = round(cv, 3)
|
||||
vmin, vmax = min(cells_v), max(cells_v)
|
||||
out["cell_voltage_min"] = round(vmin, 3)
|
||||
out["cell_voltage_max"] = round(vmax, 3)
|
||||
out["cell_voltage_delta_mv"] = round((vmax - vmin) * 1000)
|
||||
out["cell_lowest"] = cells_v.index(vmin) + 1
|
||||
out["cell_highest"] = cells_v.index(vmax) + 1
|
||||
|
||||
# --- temperatures (regs 18-21 = Temp_01..04, reg 24 = Temp_PCB) ---
|
||||
out["temperature_01"] = regs[18]
|
||||
out["temperature_02"] = regs[19]
|
||||
out["temperature_03"] = regs[20]
|
||||
out["temperature_04"] = regs[21]
|
||||
out["temperature_pcb"] = regs[24]
|
||||
|
||||
# --- SoC / SoH (regs 22, 23) ---
|
||||
out["soc"] = regs[22]
|
||||
out["soh"] = regs[23]
|
||||
|
||||
# --- heater / status (regs 25-30) ---
|
||||
# reg 30 has been observed = 1 on a healthy pack; treat as binary
|
||||
out["heater"] = "on" if regs[30] & 0x01 else "off"
|
||||
|
||||
# --- max charge/discharge current limit (reg 31), A ---
|
||||
out["max_current_limit"] = round(regs[31] / 100.0, 2)
|
||||
|
||||
# --- bitfields: warnings (reg 33), protections (reg 34), error code (reg 35) ---
|
||||
warn = regs[33]
|
||||
for i, name in enumerate(_WARNING_BITS):
|
||||
out[f"warning_{name}"] = "on" if (warn >> i) & 1 else "off"
|
||||
prot = regs[34]
|
||||
for i, name in enumerate(_PROTECTION_BITS):
|
||||
out[f"protection_{name}"] = "on" if (prot >> i) & 1 else "off"
|
||||
out["error_code"] = regs[35]
|
||||
|
||||
# --- static-ish (regs 36, 37) ---
|
||||
out["cell_count"] = regs[36]
|
||||
out["capacity_ah"] = round(regs[37] / 10.0, 1)
|
||||
out["remaining_ah"] = round(regs[38] / 100.0, 2)
|
||||
out["cycle_count"] = regs[39]
|
||||
out["battery_mode"] = regs[40]
|
||||
|
||||
# BMS firmware version — regs 41 & 42 appear to hold version codes; emit
|
||||
# the raw u16s alongside a decimal representation for easier HA display
|
||||
out["bms_version_hi"] = regs[41]
|
||||
out["bms_version_lo"] = regs[42]
|
||||
|
||||
# reg 46 increments ~1.25 Hz on live bus — likely uptime in deciseconds
|
||||
out["uptime_ds"] = regs[46]
|
||||
return out
|
||||
|
||||
|
||||
class ModbusActivePoller:
|
||||
"""One instance per pack. Opens its own serial port, issues a single
|
||||
read-holding-regs fn=0x03 on every `poll()` call, returns raw registers
|
||||
(or raises). Graceful: a pack whose port doesn't exist or whose BMS is
|
||||
off will raise on poll, and main loop catches + rate-limits the noise."""
|
||||
|
||||
READ_START = 0x0000
|
||||
READ_COUNT = 47
|
||||
|
||||
def __init__(self, port: str, baud: int, address: int, timeout_s: float = 1.0):
|
||||
self._port_path = port
|
||||
self._baud = baud
|
||||
self._address = address
|
||||
self._timeout_s = timeout_s
|
||||
self._ser: serial.Serial | None = None
|
||||
|
||||
def _open(self) -> None:
|
||||
if self._ser is None or not self._ser.is_open:
|
||||
self._ser = serial.Serial(
|
||||
port=self._port_path, baudrate=self._baud, timeout=0.2,
|
||||
bytesize=8, parity="N", stopbits=1,
|
||||
)
|
||||
|
||||
def poll(self) -> list[int]:
|
||||
self._open()
|
||||
body = bytes([self._address, 0x03,
|
||||
self.READ_START >> 8, self.READ_START & 0xFF,
|
||||
self.READ_COUNT >> 8, self.READ_COUNT & 0xFF])
|
||||
crc = crc16_modbus(body)
|
||||
frame = body + bytes([crc & 0xFF, crc >> 8])
|
||||
|
||||
assert self._ser is not None
|
||||
self._ser.reset_input_buffer()
|
||||
self._ser.write(frame)
|
||||
|
||||
expected = 3 + self.READ_COUNT * 2 + 2 # addr + func + bc + data + crc
|
||||
buf = bytearray()
|
||||
deadline = time.monotonic() + self._timeout_s
|
||||
while time.monotonic() < deadline and len(buf) < expected:
|
||||
chunk = self._ser.read(expected - len(buf))
|
||||
if chunk:
|
||||
buf.extend(chunk)
|
||||
raw = bytes(buf)
|
||||
log.debug("pack 0x%02x tx=%s rx=%s", self._address, frame.hex(" "), raw.hex(" "))
|
||||
|
||||
if len(raw) < 5 or raw[0] != self._address or raw[1] != 0x03:
|
||||
raise RuntimeError(f"no/bad response ({len(raw)} B)")
|
||||
bc = raw[2]
|
||||
if len(raw) < 3 + bc + 2:
|
||||
raise RuntimeError(f"truncated response ({len(raw)} B, expected {3 + bc + 2})")
|
||||
if not _crc_ok(raw, 0, 3 + bc + 2):
|
||||
raise RuntimeError("CRC mismatch")
|
||||
data = raw[3:3 + bc]
|
||||
return [(data[i] << 8) | data[i + 1] for i in range(0, len(data), 2)]
|
||||
|
||||
def close(self) -> None:
|
||||
if self._ser is not None and self._ser.is_open:
|
||||
self._ser.close()
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# === transports ==============================================================
|
||||
# =============================================================================
|
||||
# Two abstractions; main loop picks the right one based on bus.mode.
|
||||
|
||||
|
||||
class ActiveTransport:
|
||||
"""Request-response transport for active mode."""
|
||||
|
||||
def query_general(self, address: int) -> bytes:
|
||||
raise NotImplementedError
|
||||
|
||||
def close(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class PassiveListener:
|
||||
"""Continuous frame-iterator for passive mode."""
|
||||
|
||||
def frames(self) -> Iterator[ModbusFrame]:
|
||||
raise NotImplementedError
|
||||
|
||||
def close(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
# --- active: serial + mock --------------------------------------------------
|
||||
|
||||
|
||||
class SerialActiveTransport(ActiveTransport):
|
||||
def __init__(self, port: str, baud: int, timeout_s: float):
|
||||
self._timeout_s = timeout_s
|
||||
self._ser = serial.Serial(port=port, baudrate=baud, timeout=0.25,
|
||||
bytesize=8, parity="N", stopbits=1)
|
||||
|
||||
def query_general(self, address: int) -> bytes:
|
||||
frame = encode_eg4_request(address, CMD_GENERAL_STATUS)
|
||||
log.debug("TX addr=0x%02x: %s", address, frame.hex())
|
||||
self._ser.reset_input_buffer()
|
||||
self._ser.write(frame)
|
||||
buf = bytearray()
|
||||
deadline = time.monotonic() + self._timeout_s
|
||||
while time.monotonic() < deadline:
|
||||
chunk = self._ser.read(256)
|
||||
if chunk:
|
||||
buf.extend(chunk)
|
||||
if buf[0:1] == b"\x7E" and buf.endswith(b"\x0D"):
|
||||
break
|
||||
log.debug("RX addr=0x%02x: %s", address, bytes(buf).hex())
|
||||
return bytes(buf)
|
||||
|
||||
def close(self) -> None:
|
||||
self._ser.close()
|
||||
|
||||
|
||||
class MockActiveTransport(ActiveTransport):
|
||||
"""Synthesise EG4 7E/0D replies. Values drift per call so HA dashboards
|
||||
look alive in dry-run mode."""
|
||||
|
||||
def __init__(self, cell_count: int = 16):
|
||||
self._cell_count = cell_count
|
||||
self._call = 0
|
||||
|
||||
def query_general(self, address: int) -> bytes:
|
||||
self._call += 1
|
||||
rng = random.Random(address * 1000 + self._call)
|
||||
base_mv = 3280 + rng.randint(-5, 5)
|
||||
cells_mv = [max(0, min(0x7FFF, base_mv + rng.randint(-8, 8)))
|
||||
for _ in range(self._cell_count)]
|
||||
current_x100 = rng.randint(-500, 2000)
|
||||
current_raw = 30000 - current_x100
|
||||
soc_x100 = (50 + rng.randint(-2, 2)) * 100
|
||||
cap_ah_x100 = 5000 + rng.randint(-10, 10)
|
||||
temps_raw = [50 + 25 + rng.randint(-3, 3) for _ in range(4)]
|
||||
cycles = 42 + address
|
||||
pack_v_x100 = round(sum(cells_mv) / 10)
|
||||
|
||||
def grp(gid: int, values: list[int]) -> bytes:
|
||||
return bytes([gid, len(values)]) + b"".join(
|
||||
struct.pack(">H", v & 0xFFFF) for v in values
|
||||
)
|
||||
|
||||
body = b"".join([
|
||||
grp(0x01, cells_mv),
|
||||
grp(0x02, [current_raw]),
|
||||
grp(0x03, [soc_x100]),
|
||||
grp(0x04, [cap_ah_x100]),
|
||||
grp(0x05, temps_raw),
|
||||
grp(0x06, [0, 0]), # alarms = clear
|
||||
grp(0x07, [cycles]),
|
||||
grp(0x08, [pack_v_x100]),
|
||||
grp(0x09, []),
|
||||
grp(0x0A, []),
|
||||
])
|
||||
# checksum byte tolerated as 0x00 by the upstream parser
|
||||
return bytes([0x7E, address, CMD_GENERAL_STATUS, len(body) & 0xFF]) \
|
||||
+ body + bytes([0x00, 0x0D])
|
||||
|
||||
|
||||
# --- passive: serial + mock -------------------------------------------------
|
||||
|
||||
|
||||
class SerialPassiveListener(PassiveListener):
|
||||
_BUF_MAX = 4096
|
||||
|
||||
def __init__(self, port: str, baud: int, read_chunk: int = 512):
|
||||
self._read_chunk = read_chunk
|
||||
self._ser = serial.Serial(port=port, baudrate=baud, timeout=0.1,
|
||||
bytesize=8, parity="N", stopbits=1)
|
||||
self._buf = bytearray()
|
||||
|
||||
def frames(self) -> Iterator[ModbusFrame]:
|
||||
while True:
|
||||
chunk = self._ser.read(self._read_chunk)
|
||||
if chunk:
|
||||
self._buf.extend(chunk)
|
||||
if len(self._buf) > self._BUF_MAX:
|
||||
del self._buf[:self._BUF_MAX // 2]
|
||||
yield from self._extract()
|
||||
|
||||
def _extract(self) -> Iterator[ModbusFrame]:
|
||||
i = 0
|
||||
while i < len(self._buf) - 4:
|
||||
r = parse_modbus_frame_at(self._buf, i)
|
||||
if r is None:
|
||||
i += 1
|
||||
continue
|
||||
length, kind = r
|
||||
raw = bytes(self._buf[i:i + length])
|
||||
yield ModbusFrame(address=raw[0], function=raw[1], kind=kind, raw=raw)
|
||||
del self._buf[:i + length]
|
||||
i = 0
|
||||
|
||||
def close(self) -> None:
|
||||
self._ser.close()
|
||||
|
||||
|
||||
class MockPassiveListener(PassiveListener):
|
||||
def __init__(self, packs: list[PackConfig], gap_s: float = 0.5):
|
||||
self._packs = packs
|
||||
self._gap_s = gap_s
|
||||
self._tick = 0
|
||||
|
||||
def frames(self) -> Iterator[ModbusFrame]:
|
||||
while True:
|
||||
for pack in self._packs:
|
||||
self._tick += 1
|
||||
q = self._build_query(pack.address)
|
||||
yield ModbusFrame(address=pack.address, function=0x03, kind="query", raw=q)
|
||||
time.sleep(0.05)
|
||||
r = self._build_response(pack.address)
|
||||
yield ModbusFrame(address=pack.address, function=0x03, kind="response", raw=r)
|
||||
time.sleep(self._gap_s)
|
||||
|
||||
def _build_query(self, addr: int) -> bytes:
|
||||
body = bytes([addr, 0x03, 0x00, 0x00, 0x00, 0x2F])
|
||||
crc = crc16_modbus(body)
|
||||
return body + bytes([crc & 0xFF, crc >> 8])
|
||||
|
||||
def _build_response(self, addr: int) -> bytes:
|
||||
rng = random.Random(addr * 1000 + self._tick)
|
||||
regs = [3280 + rng.randint(-5, 5) for _ in range(16)]
|
||||
regs += [round(52.48 * 100), 50_00, rng.randint(0, 100)]
|
||||
while len(regs) < 47:
|
||||
regs.append(rng.randint(0, 100))
|
||||
body = bytes([addr, 0x03, len(regs) * 2]) + b"".join(
|
||||
struct.pack(">H", r & 0xFFFF) for r in regs
|
||||
)
|
||||
crc = crc16_modbus(body)
|
||||
return body + bytes([crc & 0xFF, crc >> 8])
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# === MQTT publisher (HA auto-discovery) ======================================
|
||||
# =============================================================================
|
||||
|
||||
|
||||
# Field metadata. Active and passive modes emit different keys; both sets
|
||||
# coexist here without overlap.
|
||||
_FIELD_META: dict[str, tuple[str | None, str | None, str | None, str | None]] = {
|
||||
# active mode (EG4 7E/0D decoded)
|
||||
"pack_voltage": ("V", "voltage", "measurement", "mdi:battery-outline"),
|
||||
"current": ("A", "current", "measurement", "mdi:current-dc"),
|
||||
"soc": ("%", "battery", "measurement", "mdi:battery-70"),
|
||||
"capacity_ah": ("Ah", None, "measurement", "mdi:battery-clock"),
|
||||
"cycle_count": (None, None, "total", "mdi:counter"),
|
||||
"cell_voltage_min": ("V", "voltage", "measurement", "mdi:arrow-down-bold"),
|
||||
"cell_voltage_max": ("V", "voltage", "measurement", "mdi:arrow-up-bold"),
|
||||
"cell_voltage_delta_mv": ("mV", None, "measurement", "mdi:sine-wave"),
|
||||
"cell_lowest": (None, None, "measurement", "mdi:numeric"),
|
||||
"cell_highest": (None, None, "measurement", "mdi:numeric"),
|
||||
"alarm_current_over": (None, None, None, "mdi:alert-octagon"),
|
||||
"alarm_voltage_high": (None, None, None, "mdi:alert"),
|
||||
"alarm_voltage_low": (None, None, None, "mdi:alert"),
|
||||
"alarm_temp_high_chg": (None, None, None, "mdi:thermometer-alert"),
|
||||
"alarm_temp_low_chg": (None, None, None, "mdi:thermometer-alert"),
|
||||
}
|
||||
for _i in range(1, 33):
|
||||
_FIELD_META[f"cell_{_i:02d}_voltage"] = ("V", "voltage", "measurement", "mdi:battery-outline")
|
||||
for _i in range(1, 7):
|
||||
_FIELD_META[f"temperature_{_i}"] = ("°C", "temperature", "measurement", "mdi:thermometer")
|
||||
# modbus_per_pack named fields (EG4 register map)
|
||||
_FIELD_META.update({
|
||||
"pack_current": ("A", "current", "measurement", "mdi:current-dc"),
|
||||
"temperature_01": ("°C", "temperature", "measurement", "mdi:thermometer"),
|
||||
"temperature_02": ("°C", "temperature", "measurement", "mdi:thermometer"),
|
||||
"temperature_03": ("°C", "temperature", "measurement", "mdi:thermometer"),
|
||||
"temperature_04": ("°C", "temperature", "measurement", "mdi:thermometer"),
|
||||
"temperature_pcb": ("°C", "temperature", "measurement", "mdi:chip"),
|
||||
"heater": (None, None, None, "mdi:heating-coil"),
|
||||
"max_current_limit": ("A", "current", "measurement", "mdi:current-dc"),
|
||||
"error_code": (None, None, None, "mdi:alert-octagon"),
|
||||
"cell_count": (None, None, "measurement", "mdi:numeric"),
|
||||
"remaining_ah": ("Ah", None, "measurement", "mdi:battery-clock"),
|
||||
"battery_mode": (None, None, None, "mdi:state-machine"),
|
||||
"bms_version_hi": (None, None, None, "mdi:chip"),
|
||||
"bms_version_lo": (None, None, None, "mdi:chip"),
|
||||
"uptime_ds": (None, None, "total_increasing", "mdi:timer-outline"),
|
||||
})
|
||||
for _name in _WARNING_BITS:
|
||||
_FIELD_META[f"warning_{_name}"] = (None, None, None, "mdi:alert")
|
||||
for _name in _PROTECTION_BITS:
|
||||
_FIELD_META[f"protection_{_name}"] = (None, None, None, "mdi:shield-alert")
|
||||
|
||||
|
||||
def field_meta(key: str) -> tuple[str | None, str | None, str | None, str | None]:
|
||||
if key.startswith("register_"):
|
||||
return (None, None, "measurement", "mdi:numeric")
|
||||
return _FIELD_META.get(key, (None, None, None, None))
|
||||
|
||||
|
||||
class MQTTPublisher:
|
||||
def __init__(self, cfg: MQTTConfig, dry_run: bool = False):
|
||||
self._cfg = cfg
|
||||
self._dry_run = dry_run
|
||||
self._client: mqtt.Client | None = None
|
||||
self._discovered: set[tuple[str, str]] = set()
|
||||
if not dry_run:
|
||||
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="eg4-battery")
|
||||
c.username_pw_set(cfg.username, cfg.password)
|
||||
c.connect(cfg.host, cfg.port, keepalive=60)
|
||||
c.loop_start()
|
||||
self._client = c
|
||||
log.info("connected to MQTT %s:%d", cfg.host, cfg.port)
|
||||
|
||||
def publish_pack(self, pack_name: str, readings: dict[str, Any]) -> None:
|
||||
for key, value in readings.items():
|
||||
self._publish_one(pack_name, key, value)
|
||||
|
||||
def _publish_one(self, pack_name: str, key: str, value: Any) -> None:
|
||||
entity_id = f"{pack_name}_{key}"
|
||||
state_topic = f"{self._cfg.discovery_prefix}/sensor/{entity_id}/state"
|
||||
disco_key = (pack_name, key)
|
||||
if disco_key not in self._discovered:
|
||||
self._publish_discovery(pack_name, key, state_topic)
|
||||
self._discovered.add(disco_key)
|
||||
payload = json.dumps(value) if isinstance(value, (dict, list)) else str(value)
|
||||
if self._dry_run:
|
||||
print(f" {state_topic} {payload}")
|
||||
else:
|
||||
self._client.publish(state_topic, payload, qos=0, retain=False)
|
||||
|
||||
def _publish_discovery(self, pack_name: str, key: str, state_topic: str) -> None:
|
||||
unit, device_class, state_class, icon = field_meta(key)
|
||||
cfg = {
|
||||
"name": f"{pack_name} {key}",
|
||||
"state_topic": state_topic,
|
||||
"unique_id": f"{pack_name}_{key}_eg4",
|
||||
"device": {
|
||||
"name": f"EG4 LifePower4 {pack_name}",
|
||||
"identifiers": [pack_name],
|
||||
"model": "LifePower4 48V 100Ah v2 Auto-Addressing",
|
||||
"manufacturer": "EG4 Electronics",
|
||||
},
|
||||
}
|
||||
if unit is not None: cfg["unit_of_measurement"] = unit
|
||||
if device_class is not None: cfg["device_class"] = device_class
|
||||
if state_class is not None: cfg["state_class"] = state_class
|
||||
if icon is not None: cfg["icon"] = icon
|
||||
topic = f"{self._cfg.discovery_prefix}/sensor/{pack_name}_{key}/config"
|
||||
payload = json.dumps(cfg)
|
||||
if self._dry_run:
|
||||
print(f" [discovery] {topic} {payload}")
|
||||
else:
|
||||
self._client.publish(topic, payload, qos=0, retain=True)
|
||||
|
||||
def close(self) -> None:
|
||||
if self._client is not None:
|
||||
self._client.loop_stop()
|
||||
self._client.disconnect()
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# === per-pack state & rate-limited logging ===================================
|
||||
# =============================================================================
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class _PackState:
|
||||
ok: bool = False
|
||||
last_error_category: str = ""
|
||||
consecutive_errors: int = 0
|
||||
response_count: int = 0
|
||||
first_seen_logged: bool = False
|
||||
|
||||
|
||||
_FAIL_HEARTBEAT_CYCLES = 360 # re-log a stuck failure every ~hour at 10 s cadence
|
||||
|
||||
|
||||
def _resolve_pack_name(addr: int, packs: list[PackConfig]) -> str:
|
||||
for p in packs:
|
||||
if p.address == addr:
|
||||
return p.name
|
||||
return f"lifepower4_addr_{addr:02x}"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# === main loops ==============================================================
|
||||
# =============================================================================
|
||||
|
||||
|
||||
def run_active(transport: ActiveTransport, publisher: MQTTPublisher, cfg: AppConfig,
|
||||
states: dict[str, _PackState], one_cycle: bool = False) -> None:
|
||||
"""Round-robin poll every configured pack; rate-limit error noise."""
|
||||
while True:
|
||||
cycle_start = time.monotonic()
|
||||
for pack in cfg.packs:
|
||||
st = states.setdefault(pack.name, _PackState())
|
||||
try:
|
||||
raw = transport.query_general(pack.address)
|
||||
if not raw:
|
||||
raise RuntimeError(f"empty response from addr=0x{pack.address:02x}")
|
||||
readings = decode_eg4_general_status(raw, cell_count=cfg.cell_count)
|
||||
publisher.publish_pack(pack.name, readings)
|
||||
st.response_count += 1
|
||||
if not st.ok and st.consecutive_errors > 0:
|
||||
log.info("pack %s (0x%02x): recovered after %d failed cycle(s)",
|
||||
pack.name, pack.address, st.consecutive_errors)
|
||||
st.ok = True
|
||||
st.consecutive_errors = 0
|
||||
except Exception as e:
|
||||
category = f"{type(e).__name__}:{str(e).split(':', 1)[0]}"
|
||||
if st.ok or category != st.last_error_category:
|
||||
log.warning("pack %s (0x%02x): %s", pack.name, pack.address, e)
|
||||
elif st.consecutive_errors > 0 and st.consecutive_errors % _FAIL_HEARTBEAT_CYCLES == 0:
|
||||
log.warning("pack %s (0x%02x): still failing (%d cycles): %s",
|
||||
pack.name, pack.address, st.consecutive_errors, e)
|
||||
st.ok = False
|
||||
st.last_error_category = category
|
||||
st.consecutive_errors += 1
|
||||
if one_cycle:
|
||||
return
|
||||
elapsed = time.monotonic() - cycle_start
|
||||
time.sleep(max(0.0, cfg.bus.poll_interval_s - elapsed))
|
||||
|
||||
|
||||
def run_passive(listener: PassiveListener, publisher: MQTTPublisher, cfg: AppConfig,
|
||||
trace: bool, max_frames: int | None = None) -> None:
|
||||
"""Consume frames as they arrive; publish on every fn=0x03 response."""
|
||||
states: dict[int, _PackState] = {}
|
||||
seen_unconfigured: set[int] = set()
|
||||
configured = {p.address for p in cfg.packs}
|
||||
n = 0
|
||||
for frame in listener.frames():
|
||||
n += 1
|
||||
if trace:
|
||||
log.debug("%r raw=%s", frame, frame.raw.hex(" "))
|
||||
if frame.kind != "response" or frame.function != 0x03:
|
||||
if max_frames is not None and n >= max_frames:
|
||||
return
|
||||
continue
|
||||
|
||||
st = states.setdefault(frame.address, _PackState())
|
||||
st.response_count += 1
|
||||
if not st.first_seen_logged:
|
||||
if frame.address in configured:
|
||||
log.info("first response from configured pack 0x%02x (%s)",
|
||||
frame.address, _resolve_pack_name(frame.address, cfg.packs))
|
||||
elif frame.address not in seen_unconfigured:
|
||||
log.warning("response from unconfigured slave 0x%02x — auto-naming as %s",
|
||||
frame.address, _resolve_pack_name(frame.address, cfg.packs))
|
||||
seen_unconfigured.add(frame.address)
|
||||
st.first_seen_logged = True
|
||||
try:
|
||||
readings = decode_modbus_response(frame)
|
||||
except Exception as e:
|
||||
log.warning("decode failed for addr 0x%02x: %s (raw=%s)",
|
||||
frame.address, e, frame.raw.hex(" "))
|
||||
continue
|
||||
publisher.publish_pack(_resolve_pack_name(frame.address, cfg.packs), readings)
|
||||
if max_frames is not None and n >= max_frames:
|
||||
return
|
||||
|
||||
|
||||
def run_modbus_per_pack(cfg: AppConfig, publisher: MQTTPublisher,
|
||||
states: dict[str, _PackState], one_cycle: bool = False,
|
||||
dry_run: bool = False) -> None:
|
||||
"""One adapter per pack. Each `PackConfig` must have `port` and `baud`
|
||||
set. Round-robin poll every pack on its own serial port; decode
|
||||
Modbus response into named HA entities + raw register_NN dump."""
|
||||
pollers: dict[str, ModbusActivePoller] = {}
|
||||
mock_regs_call: dict[str, int] = {}
|
||||
|
||||
def make_poller(p: PackConfig) -> ModbusActivePoller | None:
|
||||
if dry_run:
|
||||
return None # mock path, no real poller
|
||||
if not p.port:
|
||||
log.warning("pack %s: no `port` set in config; skipping", p.name)
|
||||
return None
|
||||
baud = p.baud or cfg.bus.baud
|
||||
try:
|
||||
return ModbusActivePoller(p.port, baud, p.address, cfg.bus.timeout_s)
|
||||
except Exception as e:
|
||||
log.warning("pack %s: could not open %s: %s", p.name, p.port, e)
|
||||
return None
|
||||
|
||||
for p in cfg.packs:
|
||||
pl = make_poller(p)
|
||||
if pl is not None:
|
||||
pollers[p.name] = pl
|
||||
|
||||
try:
|
||||
while True:
|
||||
cycle_start = time.monotonic()
|
||||
for p in cfg.packs:
|
||||
st = states.setdefault(p.name, _PackState())
|
||||
try:
|
||||
if dry_run:
|
||||
mock_regs_call[p.name] = mock_regs_call.get(p.name, 0) + 1
|
||||
regs = _mock_modbus_regs(p.address, mock_regs_call[p.name])
|
||||
else:
|
||||
if p.name not in pollers:
|
||||
raise RuntimeError(f"no poller configured for {p.name}")
|
||||
regs = pollers[p.name].poll()
|
||||
readings = decode_eg4_modbus_regs(regs)
|
||||
publisher.publish_pack(p.name, readings)
|
||||
st.response_count += 1
|
||||
if not st.ok and st.consecutive_errors > 0:
|
||||
log.info("pack %s: recovered after %d failed cycle(s)",
|
||||
p.name, st.consecutive_errors)
|
||||
st.ok = True
|
||||
st.consecutive_errors = 0
|
||||
except Exception as e:
|
||||
category = f"{type(e).__name__}:{str(e).split(':', 1)[0]}"
|
||||
if st.ok or category != st.last_error_category:
|
||||
log.warning("pack %s (0x%02x): %s", p.name, p.address, e)
|
||||
elif st.consecutive_errors > 0 \
|
||||
and st.consecutive_errors % _FAIL_HEARTBEAT_CYCLES == 0:
|
||||
log.warning("pack %s (0x%02x): still failing (%d cycles): %s",
|
||||
p.name, p.address, st.consecutive_errors, e)
|
||||
st.ok = False
|
||||
st.last_error_category = category
|
||||
st.consecutive_errors += 1
|
||||
if one_cycle:
|
||||
return
|
||||
elapsed = time.monotonic() - cycle_start
|
||||
time.sleep(max(0.0, cfg.bus.poll_interval_s - elapsed))
|
||||
finally:
|
||||
for pl in pollers.values():
|
||||
pl.close()
|
||||
|
||||
|
||||
def _mock_modbus_regs(address: int, tick: int) -> list[int]:
|
||||
"""Synthesise 47 realistic-looking registers for dry-run mode."""
|
||||
rng = random.Random(address * 1000 + tick)
|
||||
base_mv = 3280 + rng.randint(-3, 3)
|
||||
cells_mv = [base_mv + rng.randint(-8, 8) for _ in range(16)]
|
||||
regs: list[int] = [0] * 47
|
||||
regs[0] = sum(cells_mv) // 10 # pack voltage × 100
|
||||
regs[1] = (30000 - rng.randint(-500, 2000)) & 0xFFFF # current (×100 biased)
|
||||
for i, mv in enumerate(cells_mv, start=2):
|
||||
regs[i] = mv
|
||||
regs[18] = 21 + rng.randint(-1, 1)
|
||||
regs[19] = 21 + rng.randint(-1, 1)
|
||||
regs[20] = 20 + rng.randint(-1, 1)
|
||||
regs[21] = 54 + rng.randint(-1, 1)
|
||||
regs[22] = 100
|
||||
regs[23] = 100
|
||||
regs[24] = 55
|
||||
regs[30] = 1
|
||||
regs[31] = 5493
|
||||
regs[32] = 10752
|
||||
regs[33] = 0 # no warnings
|
||||
regs[34] = 0 # no protections
|
||||
regs[35] = 0 # error code
|
||||
regs[36] = 16 # cell count
|
||||
regs[37] = 1000 # 100.0 Ah
|
||||
regs[46] = (tick * 5) & 0xFFFF # runtime counter
|
||||
return regs
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(
|
||||
description="EG4 LifePower4 v2 → MQTT bridge.")
|
||||
ap.add_argument("-C", "--config", required=True, type=Path)
|
||||
ap.add_argument("--dry-run", action="store_true",
|
||||
help="Mock-bus smoke test — one cycle, print, exit.")
|
||||
ap.add_argument("--trace", action="store_true", help="Log every frame.")
|
||||
args = ap.parse_args()
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG if args.trace else logging.INFO,
|
||||
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
|
||||
)
|
||||
|
||||
cfg = load_config(args.config)
|
||||
valid_modes = {"modbus_per_pack", "active", "passive"}
|
||||
if cfg.bus.mode not in valid_modes:
|
||||
raise SystemExit(f"bus.mode must be one of {valid_modes}, got {cfg.bus.mode!r}")
|
||||
if cfg.bus.transport not in {"serial", "mock"}:
|
||||
raise SystemExit(f"bus.transport must be 'serial' or 'mock', got {cfg.bus.transport!r}")
|
||||
|
||||
publisher = MQTTPublisher(cfg.mqtt, dry_run=args.dry_run)
|
||||
log.info("eg4-battery starting: mode=%s %d configured pack(s)",
|
||||
cfg.bus.mode, len(cfg.packs))
|
||||
|
||||
use_mock = args.dry_run or cfg.bus.transport == "mock"
|
||||
|
||||
try:
|
||||
if cfg.bus.mode == "modbus_per_pack":
|
||||
run_modbus_per_pack(cfg, publisher, states={},
|
||||
one_cycle=args.dry_run, dry_run=args.dry_run)
|
||||
elif cfg.bus.mode == "active":
|
||||
transport: ActiveTransport
|
||||
transport = (MockActiveTransport(cell_count=cfg.cell_count) if use_mock
|
||||
else SerialActiveTransport(cfg.bus.port, cfg.bus.baud, cfg.bus.timeout_s))
|
||||
try:
|
||||
run_active(transport, publisher, cfg, states={}, one_cycle=args.dry_run)
|
||||
finally:
|
||||
transport.close()
|
||||
else: # passive
|
||||
listener: PassiveListener
|
||||
listener = (MockPassiveListener(cfg.packs) if use_mock
|
||||
else SerialPassiveListener(cfg.bus.port, cfg.bus.baud, cfg.bus.read_chunk))
|
||||
try:
|
||||
run_passive(listener, publisher, cfg, trace=args.trace,
|
||||
max_frames=(2 * len(cfg.packs) if args.dry_run else None))
|
||||
finally:
|
||||
listener.close()
|
||||
return 0
|
||||
except KeyboardInterrupt:
|
||||
return 0
|
||||
finally:
|
||||
publisher.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
48
eg4battery/config/eg4-battery.yaml.example
Normal file
48
eg4battery/config/eg4-battery.yaml.example
Normal file
@@ -0,0 +1,48 @@
|
||||
# eg4-battery config — deploys to ~/.config/eg4-battery/eg4-battery.yaml (mode 600)
|
||||
|
||||
bus:
|
||||
# ---- mode: pick one ----
|
||||
# active ← RECOMMENDED. We are the master on a dedicated bus to the
|
||||
# battery's pin-1/2 external monitor port. Speaks the EG4
|
||||
# 7E/0D protocol at 9600 baud. Returns named, decoded HA
|
||||
# entities (pack V, cell voltages, SoC, temps, alarms).
|
||||
#
|
||||
# passive ← Listen-only Modbus-RTU sniffer at 19200 baud. Use only when
|
||||
# the FTDI is on a bus that already has a Modbus master
|
||||
# (e.g. the LVX6048 parallel-comm bus — although see NOTES.md:
|
||||
# the LVX6048 doesn't poll EG4 packs that way, so this mode
|
||||
# is mostly diagnostic). Publishes raw `register_NN` per slave.
|
||||
mode: active
|
||||
|
||||
transport: serial # serial | mock (--dry-run on the CLI forces mock)
|
||||
|
||||
# Stable /dev/serial/by-id symlink survives USB reshuffles. Find yours with
|
||||
# ls -l /dev/serial/by-id/
|
||||
port: /dev/serial/by-id/usb-FTDI_<YOUR_ADAPTER_ID>-if00-port0
|
||||
|
||||
# Default 9600 (active EG4 protocol). Set 19200 for passive Modbus mode.
|
||||
baud: 9600
|
||||
|
||||
# Active mode only:
|
||||
timeout_s: 1.5 # per-query response wait
|
||||
poll_interval_s: 10.0 # round-robin cycle target
|
||||
|
||||
mqtt:
|
||||
host: <MQTT_BROKER_IP> # e.g. 10.0.0.41 (HA Mosquitto broker)
|
||||
port: 1883
|
||||
username: <MQTT_USER>
|
||||
password: <MQTT_PASSWORD>
|
||||
discovery_prefix: homeassistant
|
||||
|
||||
# One entry per pack. `name` is the HA entity prefix and device identifier.
|
||||
# `address` is the EG4 7E protocol address in active mode (master = 1, slaves
|
||||
# typically 2, 3, ...) or the Modbus slave ID in passive mode.
|
||||
packs:
|
||||
- name: lifepower4_1
|
||||
address: 1
|
||||
- name: lifepower4_2
|
||||
address: 2
|
||||
- name: lifepower4_3
|
||||
address: 3
|
||||
|
||||
cell_count: 16 # 16S for 48V LFP — active mode only
|
||||
19
eg4battery/etc/systemd/system/eg4-battery.service
Normal file
19
eg4battery/etc/systemd/system/eg4-battery.service
Normal file
@@ -0,0 +1,19 @@
|
||||
[Unit]
|
||||
Description=EG4 LifePower4 RS485 -> MQTT bridge
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=noise
|
||||
Group=dialout
|
||||
# Systemd's default PATH does not include ~/.local/bin where `uv` is installed.
|
||||
# The script's `#!/usr/bin/env -S uv run --script` shebang needs to find uv.
|
||||
Environment=PATH=/home/noise/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
# uv manages the ephemeral venv per the PEP-723 inline deps in the script
|
||||
ExecStart=/usr/local/bin/eg4-battery -C /home/noise/.config/eg4-battery/eg4-battery.yaml
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
5
eg4battery/etc/udev/rules.d/99-eg4-rs485.rules
Normal file
5
eg4battery/etc/udev/rules.d/99-eg4-rs485.rules
Normal file
@@ -0,0 +1,5 @@
|
||||
# EG4 LifePower4 RS485 bus via USB-serial adapter.
|
||||
# Grants dialout group access; /dev/serial/by-id/ symlink survives USB moves.
|
||||
# Adjust idVendor/idProduct if you use a CP210x (0x10c4:0xea60) or CH340
|
||||
# (0x1a86:0x7523) adapter instead of the reference FTDI FT232R.
|
||||
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0660", GROUP="dialout"
|
||||
58
eg4battery/homeassistant/README.md
Normal file
58
eg4battery/homeassistant/README.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# HA-side configuration for the eg4-battery daemon
|
||||
|
||||
Reference configs that go into your Home Assistant instance — they aren't
|
||||
installed by `install.sh` (HA typically lives on a different host / in an
|
||||
HA OS appliance), but they're tracked here so the full stack is reproducible.
|
||||
|
||||
## What's in here
|
||||
|
||||
| File | Where it goes in HA |
|
||||
|---------------------------|-----------------------------------------------------|
|
||||
| `recorder.yaml` | `configuration.yaml` → under a `recorder:` key, or merge into existing |
|
||||
| `template_sensors.yaml` | `configuration.yaml` → under a top-level `template:` list, or include via `!include` |
|
||||
| `lovelace_overview.yaml` | Raw Lovelace card config — paste into a new dashboard view |
|
||||
|
||||
All of it assumes pack names `lifepower4_1`, `lifepower4_2`, `lifepower4_3`
|
||||
matching the daemon's default config. If you renamed your packs, do a
|
||||
`sed -i 's/lifepower4_/your_prefix_/' *.yaml` first.
|
||||
|
||||
## Recommended retention tiers
|
||||
|
||||
Full rationale in [`../NOTES.md`](../NOTES.md) and the architecture thread,
|
||||
but the short version:
|
||||
|
||||
- **Tier 1 — keep forever**: `pack_voltage`, `pack_current`, `soc`, `soh`,
|
||||
`cycle_count`, `cell_voltage_min/max/delta_mv`, `capacity_ah`.
|
||||
- **Tier 2 — keep short**: all 14 `warning_*` + 14 `protection_*`,
|
||||
`error_code`, `remaining_ah`, `heater`, the derived `temperature_max`
|
||||
and `pack_power`.
|
||||
- **Tier 3 — exclude** (the `recorder.yaml` here does this): all 47 raw
|
||||
`register_NN` entities, the 16 individual `cell_NN_voltage` series,
|
||||
static metadata (`bms_version_*`, `battery_mode`, `cell_count`, etc.),
|
||||
and the `uptime_ds` counter that increments every second.
|
||||
|
||||
## Enabling in HA
|
||||
|
||||
Easiest path:
|
||||
|
||||
```yaml
|
||||
# configuration.yaml
|
||||
|
||||
# merge our recorder exclusions with your existing recorder config
|
||||
recorder: !include eg4_battery/recorder.yaml
|
||||
|
||||
# include the template sensors (creates a new `template:` list block)
|
||||
template: !include eg4_battery/template_sensors.yaml
|
||||
```
|
||||
|
||||
And drop the two YAMLs into `~/homeassistant/eg4_battery/`.
|
||||
|
||||
If you already have `recorder:` or `template:` keys elsewhere, merge by
|
||||
hand — HA doesn't allow two definitions of the same top-level key.
|
||||
|
||||
## Energy dashboard wiring (optional)
|
||||
|
||||
Once the derived `pack_power` template sensors exist, add them to the
|
||||
Energy dashboard via **Settings → Dashboards → Energy → Home battery
|
||||
storage** — each pack's `pack_power` integrates to `pack_energy_in_kwh`
|
||||
and `pack_energy_out_kwh` automatically, with per-pack bars.
|
||||
116
eg4battery/homeassistant/lovelace_overview.yaml
Normal file
116
eg4battery/homeassistant/lovelace_overview.yaml
Normal file
@@ -0,0 +1,116 @@
|
||||
# Lovelace card config for a 3-pack LifePower4 stack overview.
|
||||
# Paste into a dashboard view's raw-config editor, or drop in as a YAML-mode
|
||||
# dashboard. Assumes the template sensors in template_sensors.yaml exist.
|
||||
|
||||
views:
|
||||
- title: Battery Stack
|
||||
icon: mdi:battery
|
||||
path: batteries
|
||||
cards:
|
||||
# ---- stack summary row ----
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
- type: gauge
|
||||
name: Stack SoC
|
||||
entity: sensor.lifepower4_stack_soc_avg
|
||||
min: 0
|
||||
max: 100
|
||||
severity:
|
||||
green: 40
|
||||
yellow: 20
|
||||
red: 0
|
||||
- type: entity
|
||||
name: Stack Power
|
||||
entity: sensor.lifepower4_stack_pack_power_total
|
||||
icon: mdi:flash
|
||||
- type: entity
|
||||
name: Hottest Point
|
||||
entity: sensor.lifepower4_stack_temperature_max
|
||||
icon: mdi:thermometer
|
||||
|
||||
# ---- per-pack summary cards ----
|
||||
- type: horizontal-stack
|
||||
cards:
|
||||
- !include_named pack_summary_pack1.yaml
|
||||
- !include_named pack_summary_pack2.yaml
|
||||
- !include_named pack_summary_pack3.yaml
|
||||
|
||||
# ---- pack voltage time series ----
|
||||
- type: history-graph
|
||||
title: Pack voltage (24 h)
|
||||
hours_to_show: 24
|
||||
entities:
|
||||
- sensor.lifepower4_1_pack_voltage
|
||||
- sensor.lifepower4_2_pack_voltage
|
||||
- sensor.lifepower4_3_pack_voltage
|
||||
|
||||
# ---- SoC + SoH trend ----
|
||||
- type: history-graph
|
||||
title: SoC / SoH
|
||||
hours_to_show: 168 # 1 week
|
||||
entities:
|
||||
- sensor.lifepower4_1_soc
|
||||
- sensor.lifepower4_2_soc
|
||||
- sensor.lifepower4_3_soc
|
||||
- sensor.lifepower4_1_soh
|
||||
- sensor.lifepower4_2_soh
|
||||
- sensor.lifepower4_3_soh
|
||||
|
||||
# ---- cell balance health (the crucial long-term metric) ----
|
||||
- type: history-graph
|
||||
title: Cell voltage delta (mV) — rising = balance degrading
|
||||
hours_to_show: 168
|
||||
entities:
|
||||
- sensor.lifepower4_1_cell_voltage_delta_mv
|
||||
- sensor.lifepower4_2_cell_voltage_delta_mv
|
||||
- sensor.lifepower4_3_cell_voltage_delta_mv
|
||||
|
||||
# ---- any active warnings/protections — glance card, visible red when on ----
|
||||
- type: entities
|
||||
title: Alarms (should all be "off" on a healthy stack)
|
||||
show_header_toggle: false
|
||||
entities:
|
||||
- type: section
|
||||
label: Pack 1
|
||||
- entity: sensor.lifepower4_1_warning_cell_ov
|
||||
name: Cell OV
|
||||
- entity: sensor.lifepower4_1_warning_cell_uv
|
||||
name: Cell UV
|
||||
- entity: sensor.lifepower4_1_warning_charge_oc
|
||||
name: Charge OC
|
||||
- entity: sensor.lifepower4_1_warning_discharge_oc
|
||||
name: Discharge OC
|
||||
- entity: sensor.lifepower4_1_warning_mos_ot
|
||||
name: MOSFET OT
|
||||
- entity: sensor.lifepower4_1_warning_low_capacity
|
||||
name: Low Capacity
|
||||
- entity: sensor.lifepower4_1_protection_cell_ov
|
||||
name: PROT Cell OV
|
||||
- entity: sensor.lifepower4_1_protection_cell_uv
|
||||
name: PROT Cell UV
|
||||
# (repeat structure for pack_2 and pack_3, omitted for brevity)
|
||||
|
||||
# Per-pack summary card template — save as three copies named
|
||||
# pack_summary_pack1.yaml, pack_summary_pack2.yaml, pack_summary_pack3.yaml
|
||||
# with only the N suffix different.
|
||||
#
|
||||
# type: entities
|
||||
# title: Pack 1
|
||||
# show_header_toggle: false
|
||||
# entities:
|
||||
# - entity: sensor.lifepower4_1_pack_voltage
|
||||
# name: Voltage
|
||||
# - entity: sensor.lifepower4_1_pack_current
|
||||
# name: Current
|
||||
# - entity: sensor.lifepower4_1_pack_power
|
||||
# name: Power
|
||||
# - entity: sensor.lifepower4_1_soc
|
||||
# name: SoC
|
||||
# - entity: sensor.lifepower4_1_soh
|
||||
# name: SoH
|
||||
# - entity: sensor.lifepower4_1_temperature_max
|
||||
# name: Hottest
|
||||
# - entity: sensor.lifepower4_1_cell_voltage_delta_mv
|
||||
# name: Cell Δ
|
||||
# - entity: sensor.lifepower4_1_cycle_count
|
||||
# name: Cycles
|
||||
51
eg4battery/homeassistant/recorder.yaml
Normal file
51
eg4battery/homeassistant/recorder.yaml
Normal file
@@ -0,0 +1,51 @@
|
||||
# HA recorder exclusions for the eg4-battery daemon's MQTT entities.
|
||||
#
|
||||
# Merge with your existing recorder config; if you don't have one, this whole
|
||||
# file can be referenced as `recorder: !include eg4_battery/recorder.yaml`.
|
||||
#
|
||||
# Rationale:
|
||||
# - register_NN entities are raw Modbus registers, diagnostic only
|
||||
# - individual cell voltages are redundant once you have min/max/delta
|
||||
# - uptime / version / static config values are pure noise in a timeseries
|
||||
#
|
||||
# Everything NOT in `entity_globs` below keeps recording normally, including
|
||||
# the Tier-1 (pack_voltage / soc / soh / cycle_count / cell_voltage_min/max/
|
||||
# delta_mv / capacity_ah) and Tier-2 (warnings / protections / error_code)
|
||||
# entities. See ../NOTES.md for the retention-tier breakdown.
|
||||
|
||||
exclude:
|
||||
entity_globs:
|
||||
# raw Modbus register dump — diagnostic only
|
||||
- sensor.lifepower4_*_register_*
|
||||
|
||||
# 16 individual cells per pack = 48 noisy series.
|
||||
# cell_voltage_min / _max / _delta_mv already capture 95% of the info.
|
||||
# Comment this out if you're debugging a specific drifting cell.
|
||||
- sensor.lifepower4_*_cell_01_voltage
|
||||
- sensor.lifepower4_*_cell_02_voltage
|
||||
- sensor.lifepower4_*_cell_03_voltage
|
||||
- sensor.lifepower4_*_cell_04_voltage
|
||||
- sensor.lifepower4_*_cell_05_voltage
|
||||
- sensor.lifepower4_*_cell_06_voltage
|
||||
- sensor.lifepower4_*_cell_07_voltage
|
||||
- sensor.lifepower4_*_cell_08_voltage
|
||||
- sensor.lifepower4_*_cell_09_voltage
|
||||
- sensor.lifepower4_*_cell_10_voltage
|
||||
- sensor.lifepower4_*_cell_11_voltage
|
||||
- sensor.lifepower4_*_cell_12_voltage
|
||||
- sensor.lifepower4_*_cell_13_voltage
|
||||
- sensor.lifepower4_*_cell_14_voltage
|
||||
- sensor.lifepower4_*_cell_15_voltage
|
||||
- sensor.lifepower4_*_cell_16_voltage
|
||||
|
||||
# static metadata (doesn't change, no reason to keep history)
|
||||
- sensor.lifepower4_*_bms_version_hi
|
||||
- sensor.lifepower4_*_bms_version_lo
|
||||
- sensor.lifepower4_*_cell_count
|
||||
- sensor.lifepower4_*_cell_highest
|
||||
- sensor.lifepower4_*_cell_lowest
|
||||
- sensor.lifepower4_*_battery_mode
|
||||
- sensor.lifepower4_*_max_current_limit
|
||||
|
||||
# uptime counter — increments every second, kills the recorder's write cache
|
||||
- sensor.lifepower4_*_uptime_ds
|
||||
174
eg4battery/homeassistant/template_sensors.yaml
Normal file
174
eg4battery/homeassistant/template_sensors.yaml
Normal file
@@ -0,0 +1,174 @@
|
||||
# Derived template sensors for the eg4-battery daemon's 3-pack stack.
|
||||
# Include into configuration.yaml as:
|
||||
# template: !include eg4_battery/template_sensors.yaml
|
||||
#
|
||||
# Per-pack entities created:
|
||||
# sensor.lifepower4_N_pack_power W (V × I, signed; + = charging)
|
||||
# sensor.lifepower4_N_temperature_max °C (max of 5 temp sensors)
|
||||
# sensor.lifepower4_N_cell_imbalance_pct % (delta / min_cell) × 100
|
||||
#
|
||||
# Stack-wide rollups:
|
||||
# sensor.lifepower4_stack_pack_power_total W (sum of all 3 pack_powers)
|
||||
# sensor.lifepower4_stack_soc_avg % (average SoC across packs)
|
||||
# sensor.lifepower4_stack_temperature_max °C (hottest point anywhere)
|
||||
|
||||
- sensor:
|
||||
# ---- pack 1 ----
|
||||
- name: "lifepower4_1 pack_power"
|
||||
unique_id: lifepower4_1_pack_power
|
||||
unit_of_measurement: "W"
|
||||
device_class: power
|
||||
state_class: measurement
|
||||
state: >
|
||||
{% set v = states('sensor.lifepower4_1_pack_voltage') | float(0) %}
|
||||
{% set i = states('sensor.lifepower4_1_pack_current') | float(0) %}
|
||||
{{ (v * i) | round(1) }}
|
||||
|
||||
- name: "lifepower4_1 temperature_max"
|
||||
unique_id: lifepower4_1_temperature_max
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
state: >
|
||||
{% set t = [
|
||||
states('sensor.lifepower4_1_temperature_01') | int(0),
|
||||
states('sensor.lifepower4_1_temperature_02') | int(0),
|
||||
states('sensor.lifepower4_1_temperature_03') | int(0),
|
||||
states('sensor.lifepower4_1_temperature_04') | int(0),
|
||||
states('sensor.lifepower4_1_temperature_pcb') | int(0),
|
||||
] %}
|
||||
{{ t | max }}
|
||||
|
||||
- name: "lifepower4_1 cell_imbalance_pct"
|
||||
unique_id: lifepower4_1_cell_imbalance_pct
|
||||
unit_of_measurement: "%"
|
||||
state_class: measurement
|
||||
state: >
|
||||
{% set d = states('sensor.lifepower4_1_cell_voltage_delta_mv') | float(0) %}
|
||||
{% set mn = states('sensor.lifepower4_1_cell_voltage_min') | float(0) %}
|
||||
{{ (d / (mn * 1000) * 100) | round(3) if mn > 0 else 0 }}
|
||||
|
||||
# ---- pack 2 ----
|
||||
- name: "lifepower4_2 pack_power"
|
||||
unique_id: lifepower4_2_pack_power
|
||||
unit_of_measurement: "W"
|
||||
device_class: power
|
||||
state_class: measurement
|
||||
state: >
|
||||
{% set v = states('sensor.lifepower4_2_pack_voltage') | float(0) %}
|
||||
{% set i = states('sensor.lifepower4_2_pack_current') | float(0) %}
|
||||
{{ (v * i) | round(1) }}
|
||||
|
||||
- name: "lifepower4_2 temperature_max"
|
||||
unique_id: lifepower4_2_temperature_max
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
state: >
|
||||
{% set t = [
|
||||
states('sensor.lifepower4_2_temperature_01') | int(0),
|
||||
states('sensor.lifepower4_2_temperature_02') | int(0),
|
||||
states('sensor.lifepower4_2_temperature_03') | int(0),
|
||||
states('sensor.lifepower4_2_temperature_04') | int(0),
|
||||
states('sensor.lifepower4_2_temperature_pcb') | int(0),
|
||||
] %}
|
||||
{{ t | max }}
|
||||
|
||||
- name: "lifepower4_2 cell_imbalance_pct"
|
||||
unique_id: lifepower4_2_cell_imbalance_pct
|
||||
unit_of_measurement: "%"
|
||||
state_class: measurement
|
||||
state: >
|
||||
{% set d = states('sensor.lifepower4_2_cell_voltage_delta_mv') | float(0) %}
|
||||
{% set mn = states('sensor.lifepower4_2_cell_voltage_min') | float(0) %}
|
||||
{{ (d / (mn * 1000) * 100) | round(3) if mn > 0 else 0 }}
|
||||
|
||||
# ---- pack 3 ----
|
||||
- name: "lifepower4_3 pack_power"
|
||||
unique_id: lifepower4_3_pack_power
|
||||
unit_of_measurement: "W"
|
||||
device_class: power
|
||||
state_class: measurement
|
||||
state: >
|
||||
{% set v = states('sensor.lifepower4_3_pack_voltage') | float(0) %}
|
||||
{% set i = states('sensor.lifepower4_3_pack_current') | float(0) %}
|
||||
{{ (v * i) | round(1) }}
|
||||
|
||||
- name: "lifepower4_3 temperature_max"
|
||||
unique_id: lifepower4_3_temperature_max
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
state: >
|
||||
{% set t = [
|
||||
states('sensor.lifepower4_3_temperature_01') | int(0),
|
||||
states('sensor.lifepower4_3_temperature_02') | int(0),
|
||||
states('sensor.lifepower4_3_temperature_03') | int(0),
|
||||
states('sensor.lifepower4_3_temperature_04') | int(0),
|
||||
states('sensor.lifepower4_3_temperature_pcb') | int(0),
|
||||
] %}
|
||||
{{ t | max }}
|
||||
|
||||
- name: "lifepower4_3 cell_imbalance_pct"
|
||||
unique_id: lifepower4_3_cell_imbalance_pct
|
||||
unit_of_measurement: "%"
|
||||
state_class: measurement
|
||||
state: >
|
||||
{% set d = states('sensor.lifepower4_3_cell_voltage_delta_mv') | float(0) %}
|
||||
{% set mn = states('sensor.lifepower4_3_cell_voltage_min') | float(0) %}
|
||||
{{ (d / (mn * 1000) * 100) | round(3) if mn > 0 else 0 }}
|
||||
|
||||
# ---- stack-wide rollups ----
|
||||
- name: "lifepower4_stack pack_power_total"
|
||||
unique_id: lifepower4_stack_pack_power_total
|
||||
unit_of_measurement: "W"
|
||||
device_class: power
|
||||
state_class: measurement
|
||||
state: >
|
||||
{% set p = [
|
||||
states('sensor.lifepower4_1_pack_power') | float(0),
|
||||
states('sensor.lifepower4_2_pack_power') | float(0),
|
||||
states('sensor.lifepower4_3_pack_power') | float(0),
|
||||
] %}
|
||||
{{ p | sum | round(1) }}
|
||||
|
||||
- name: "lifepower4_stack soc_avg"
|
||||
unique_id: lifepower4_stack_soc_avg
|
||||
unit_of_measurement: "%"
|
||||
device_class: battery
|
||||
state_class: measurement
|
||||
state: >
|
||||
{% set s = [
|
||||
states('sensor.lifepower4_1_soc') | float(0),
|
||||
states('sensor.lifepower4_2_soc') | float(0),
|
||||
states('sensor.lifepower4_3_soc') | float(0),
|
||||
] %}
|
||||
{{ (s | sum / s | length) | round(1) }}
|
||||
|
||||
- name: "lifepower4_stack temperature_max"
|
||||
unique_id: lifepower4_stack_temperature_max
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
state: >
|
||||
{% set t = [
|
||||
states('sensor.lifepower4_1_temperature_max') | int(0),
|
||||
states('sensor.lifepower4_2_temperature_max') | int(0),
|
||||
states('sensor.lifepower4_3_temperature_max') | int(0),
|
||||
] %}
|
||||
{{ t | max }}
|
||||
|
||||
# --- integration → energy (pack_power integrated to Wh) ---
|
||||
# Paste this at the top level of configuration.yaml, NOT inside `template:`:
|
||||
#
|
||||
# sensor:
|
||||
# - platform: integration
|
||||
# source: sensor.lifepower4_1_pack_power
|
||||
# name: lifepower4_1_pack_energy
|
||||
# unit_prefix: k
|
||||
# round: 3
|
||||
# method: left
|
||||
# # ... repeat for pack 2 and 3 ...
|
||||
#
|
||||
# Then wire the resulting sensor.lifepower4_N_pack_energy into the HA
|
||||
# Energy dashboard → Home battery storage → one entry per pack.
|
||||
93
eg4battery/install.sh
Executable file
93
eg4battery/install.sh
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env bash
|
||||
# EG4 LifePower4 → Home Assistant monitoring — reproducible installer.
|
||||
#
|
||||
# Installs the eg4-battery daemon onto /usr/local/bin (uv handles deps via the
|
||||
# script's PEP-723 inline metadata), drops in the udev rule + systemd unit,
|
||||
# and seeds the config template. Idempotent: safe to re-run.
|
||||
#
|
||||
# Assumptions:
|
||||
# - Debian-family Linux with systemd
|
||||
# - `uv` on $PATH (https://docs.astral.sh/uv/)
|
||||
# - User has sudo
|
||||
#
|
||||
# After install, finish by editing:
|
||||
# ~/.config/eg4-battery/eg4-battery.yaml — bus.port, MQTT creds, pack addresses
|
||||
# then:
|
||||
# ./install.sh --dry-run — end-to-end smoke test (no HW needed)
|
||||
# sudo systemctl enable --now eg4-battery.service
|
||||
# journalctl -u eg4-battery.service -f
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BASE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DRY_RUN=0
|
||||
for arg in "$@"; do
|
||||
[ "$arg" = "--dry-run" ] && DRY_RUN=1
|
||||
done
|
||||
|
||||
msg() { printf '\n\033[1;36m== %s ==\033[0m\n' "$*"; }
|
||||
|
||||
# --- 1. dependency check ---------------------------------------------------
|
||||
msg "Checking prerequisites"
|
||||
command -v uv >/dev/null || { echo "uv not found — install from https://docs.astral.sh/uv/"; exit 1; }
|
||||
|
||||
# --- 2. entry point --------------------------------------------------------
|
||||
msg "Installing /usr/local/bin/eg4-battery"
|
||||
sudo install -m 755 "${BASE}/bin/eg4-battery" /usr/local/bin/eg4-battery
|
||||
|
||||
# --- 3. udev rule ----------------------------------------------------------
|
||||
msg "Installing udev rule (FTDI/CH340/CP210x → dialout)"
|
||||
sudo install -m 644 "${BASE}/etc/udev/rules.d/99-eg4-rs485.rules" /etc/udev/rules.d/99-eg4-rs485.rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger --subsystem-match=tty
|
||||
|
||||
# --- 4. systemd unit -------------------------------------------------------
|
||||
msg "Installing systemd unit"
|
||||
sudo install -m 644 "${BASE}/etc/systemd/system/eg4-battery.service" /etc/systemd/system/eg4-battery.service
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
# --- 5. user config (only if not already present) --------------------------
|
||||
msg "Installing config template"
|
||||
mkdir -p "${HOME}/.config/eg4-battery"
|
||||
dest="${HOME}/.config/eg4-battery/eg4-battery.yaml"
|
||||
if [ -e "$dest" ]; then
|
||||
echo " $dest already exists — not overwriting"
|
||||
else
|
||||
install -m 600 "${BASE}/config/eg4-battery.yaml.example" "$dest"
|
||||
echo " wrote $dest (mode 600) — edit bus.port, MQTT creds, pack addresses"
|
||||
fi
|
||||
|
||||
# --- 6. smoke test ---------------------------------------------------------
|
||||
if [ "$DRY_RUN" = "1" ]; then
|
||||
msg "Dry-run: running one mock-bus cycle (no MQTT publish)"
|
||||
/usr/local/bin/eg4-battery -C "$dest" --dry-run
|
||||
echo
|
||||
echo "(above output is what would be published to MQTT under real run)"
|
||||
fi
|
||||
|
||||
# --- 7. enable -------------------------------------------------------------
|
||||
if grep -q '<MQTT_PASSWORD>' "$dest" 2>/dev/null; then
|
||||
cat <<EOF
|
||||
|
||||
Credentials in $dest still contain a placeholder.
|
||||
Edit the file, verify with: eg4-battery -C $dest --dry-run
|
||||
Then enable the daemon:
|
||||
|
||||
sudo systemctl enable --now eg4-battery.service
|
||||
journalctl -u eg4-battery.service -f
|
||||
|
||||
EOF
|
||||
else
|
||||
msg "Enabling eg4-battery.service"
|
||||
sudo systemctl enable --now eg4-battery.service
|
||||
sleep 3
|
||||
systemctl --no-pager status eg4-battery.service | head -15
|
||||
fi
|
||||
|
||||
msg "Done"
|
||||
echo "Next steps:"
|
||||
echo " - While batteries are still in the mail: ./install.sh --dry-run"
|
||||
echo " - Once one pack is wired: edit ~/.config/eg4-battery/eg4-battery.yaml,"
|
||||
echo " set bus.transport: serial + address: 1 only,"
|
||||
echo " validate per ../NOTES.md"
|
||||
echo " - Full three-pack bring-up: uncomment addresses 2 and 3"
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtCore</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtCore</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = corelib.pro
|
||||
QMAKE_PRL_TARGET = QtCore
|
||||
QMAKE_PRL_CONFIG = lex yacc exceptions depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs testcase_exceptions explicitlib testcase_no_bundle warning_clean exceptions qt_tracepoints moc resources simd optimize_full pcre2 generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle arch_haswell avx512common avx512core thread
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtCore</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtCore</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = corelib.pro
|
||||
QMAKE_PRL_TARGET = QtCore
|
||||
QMAKE_PRL_CONFIG = lex yacc exceptions depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs testcase_exceptions explicitlib testcase_no_bundle warning_clean exceptions qt_tracepoints moc resources simd optimize_full pcre2 generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle arch_haswell avx512common avx512core thread
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtCore</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtCore</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = corelib.pro
|
||||
QMAKE_PRL_TARGET = QtCore
|
||||
QMAKE_PRL_CONFIG = lex yacc exceptions depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs testcase_exceptions explicitlib testcase_no_bundle warning_clean exceptions qt_tracepoints moc resources simd optimize_full pcre2 generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle arch_haswell avx512common avx512core thread
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtDBus</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtDBus</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = dbus.pro
|
||||
QMAKE_PRL_TARGET = QtDBus
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtDBus</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtDBus</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = dbus.pro
|
||||
QMAKE_PRL_TARGET = QtDBus
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtDBus</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtDBus</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = dbus.pro
|
||||
QMAKE_PRL_TARGET = QtDBus
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtGui</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtGui</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = gui.pro
|
||||
QMAKE_PRL_TARGET = QtGui
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean simd optimize_full opengl generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc qt_tracepoints have_target dll debug_info objective_c any_bundle arch_haswell avx512common avx512core thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework AppKit -framework Metal -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;AppKit;-framework;Metal;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtGui</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtGui</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = gui.pro
|
||||
QMAKE_PRL_TARGET = QtGui
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean simd optimize_full opengl generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc qt_tracepoints have_target dll debug_info objective_c any_bundle arch_haswell avx512common avx512core thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework AppKit -framework Metal -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;AppKit;-framework;Metal;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtGui</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtGui</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = gui.pro
|
||||
QMAKE_PRL_TARGET = QtGui
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean simd optimize_full opengl generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc qt_tracepoints have_target dll debug_info objective_c any_bundle arch_haswell avx512common avx512core thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework AppKit -framework Metal -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;AppKit;-framework;Metal;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtNetwork</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtNetwork</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = network.pro
|
||||
QMAKE_PRL_TARGET = QtNetwork
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtNetwork</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtNetwork</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = network.pro
|
||||
QMAKE_PRL_TARGET = QtNetwork
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtNetwork</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtNetwork</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = network.pro
|
||||
QMAKE_PRL_TARGET = QtNetwork
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtPrintSupport</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtPrintSupport</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = printsupport.pro
|
||||
QMAKE_PRL_TARGET = QtPrintSupport
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread uic opengl moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtWidgets -framework QtGui -framework AppKit -framework Metal -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtWidgets;-framework;QtGui;-framework;AppKit;-framework;Metal;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtPrintSupport</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtPrintSupport</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = printsupport.pro
|
||||
QMAKE_PRL_TARGET = QtPrintSupport
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread uic opengl moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtWidgets -framework QtGui -framework AppKit -framework Metal -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtWidgets;-framework;QtGui;-framework;AppKit;-framework;Metal;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtPrintSupport</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtPrintSupport</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = printsupport.pro
|
||||
QMAKE_PRL_TARGET = QtPrintSupport
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread uic opengl moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtWidgets -framework QtGui -framework AppKit -framework Metal -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtWidgets;-framework;QtGui;-framework;AppKit;-framework;Metal;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtQml</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtQml</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = qml.pro
|
||||
QMAKE_PRL_TARGET = QtQml
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean python_available qt_tracepoints qlalr generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtNetwork -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtNetwork;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtQml</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtQml</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = qml.pro
|
||||
QMAKE_PRL_TARGET = QtQml
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean python_available qt_tracepoints qlalr generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtNetwork -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtNetwork;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtQml</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtQml</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = qml.pro
|
||||
QMAKE_PRL_TARGET = QtQml
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean python_available qt_tracepoints qlalr generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtNetwork -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtNetwork;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtQmlModels</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtQmlModels</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = qmlmodels.pro
|
||||
QMAKE_PRL_TARGET = QtQmlModels
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean python_available generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -F$$[QT_INSTALL_LIBS] -framework QtQml -framework QtNetwork -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-F$$[QT_INSTALL_LIBS];-framework;QtQml;-framework;QtNetwork;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtQmlModels</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtQmlModels</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = qmlmodels.pro
|
||||
QMAKE_PRL_TARGET = QtQmlModels
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean python_available generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -F$$[QT_INSTALL_LIBS] -framework QtQml -framework QtNetwork -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-F$$[QT_INSTALL_LIBS];-framework;QtQml;-framework;QtNetwork;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtQmlModels</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtQmlModels</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = qmlmodels.pro
|
||||
QMAKE_PRL_TARGET = QtQmlModels
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean python_available generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -F$$[QT_INSTALL_LIBS] -framework QtQml -framework QtNetwork -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-F$$[QT_INSTALL_LIBS];-framework;QtQml;-framework;QtNetwork;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtQuick</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtQuick</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = quick.pro
|
||||
QMAKE_PRL_TARGET = QtQuick
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean python_available generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread opengl moc resources moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -F$$[QT_INSTALL_LIBS] -framework QtQmlModels -framework QtQml -framework QtGui -framework AppKit -framework Metal -framework QtNetwork -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-F$$[QT_INSTALL_LIBS];-framework;QtQmlModels;-framework;QtQml;-framework;QtGui;-framework;AppKit;-framework;Metal;-framework;QtNetwork;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtQuick</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtQuick</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = quick.pro
|
||||
QMAKE_PRL_TARGET = QtQuick
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean python_available generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread opengl moc resources moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -F$$[QT_INSTALL_LIBS] -framework QtQmlModels -framework QtQml -framework QtGui -framework AppKit -framework Metal -framework QtNetwork -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-F$$[QT_INSTALL_LIBS];-framework;QtQmlModels;-framework;QtQml;-framework;QtGui;-framework;AppKit;-framework;Metal;-framework;QtNetwork;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtQuick</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtQuick</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = quick.pro
|
||||
QMAKE_PRL_TARGET = QtQuick
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean python_available generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread opengl moc resources moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -F$$[QT_INSTALL_LIBS] -framework QtQmlModels -framework QtQml -framework QtGui -framework AppKit -framework Metal -framework QtNetwork -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-F$$[QT_INSTALL_LIBS];-framework;QtQmlModels;-framework;QtQml;-framework;QtGui;-framework;AppKit;-framework;Metal;-framework;QtNetwork;-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtSerialPort</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtSerialPort</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = serialport.pro
|
||||
QMAKE_PRL_TARGET = QtSerialPort
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle done_config_ntddmodm generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtSerialPort</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtSerialPort</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = serialport.pro
|
||||
QMAKE_PRL_TARGET = QtSerialPort
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle done_config_ntddmodm generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtSerialPort</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtSerialPort</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = serialport.pro
|
||||
QMAKE_PRL_TARGET = QtSerialPort
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle done_config_ntddmodm generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtSql</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtSql</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = sql.pro
|
||||
QMAKE_PRL_TARGET = QtSql
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>QtSql</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.qt-project.QtSql</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>5.14.2</string>
|
||||
<key>NOTE</key>
|
||||
<string>Please, do NOT change this file -- It was generated by Qt/QMake.</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
QMAKE_PRO_INPUT = sql.pro
|
||||
QMAKE_PRL_TARGET = QtSql
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin asset_catalogs rez prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl app_bundle incremental global_init_link_order lib_version_first sdk clang_pch_style shared shared qt_framework release macos osx macx mac darwin unix posix gcc clang llvm sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd shani x86SimdAlways prefix_build force_independent no_warn_empty_obj_files utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions explicitlib testcase_no_bundle warning_clean generated_privates module_frameworks lib_bundle relative_qt_rpath app_extension_api_only git_build target_qt c++11 strict_c++ c++14 c99 c11 hide_symbols separate_debug_info need_fwd_pri qt_install_module create_cmake sliced_bundle compiler_supports_fpmath create_pc have_target dll debug_info objective_c any_bundle thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.14.2
|
||||
QMAKE_PRL_LIBS = -F$$[QT_INSTALL_LIBS] -framework QtCore -framework DiskArbitration -framework IOKit
|
||||
QMAKE_PRL_LIBS_FOR_CMAKE = -F$$[QT_INSTALL_LIBS];-framework;QtCore;-framework;DiskArbitration;-framework;IOKit;
|
||||
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user