Merged the different forks that are floating around and tested this on my Primary/ Secondary LUX 3600ACS set-up

This commit is contained in:
AndyWhittaker 2021-05-18 16:30:54 +01:00
parent 6dd86bb946
commit 8f3d9b9cf6
12 changed files with 139 additions and 204 deletions

View File

@ -16,9 +16,7 @@ After the datalogger reboots (this takes only a couple of seconds and does not a
## Enabling AC Charge
You may need to tweak a setting to enable AC Charging. This is easiest done on LuxPower's web portal, and the phone apps will let you do it too especially if you can connect locally to the inverter's dongle rather than connect via China (can be a bit slow with numerous timeouts).
The trick with these apps is to select your inverter from the dropdown listbox above and then press "Read". If not connected locally, this can take 2 minutes to work. If you think it hasn't worked, just click "Read" again but be patient. After inputting you new values, press the "Set" button. Again, this can take at least a minute to work - you should see a "Success" message pop-up, otherwise "Timed Out" will appear; if this happens, just press the "Set" button once again.
You may need to tweak a setting to enable AC Charging. This is easiest done on LuxPower's web portal, and the phone apps will let you do it too.
Check that `AC Charge Start Time 1` and `AC Charge End Time 1` are `00:00` and `23:59` respectively, as seen in this screenshot:
@ -26,4 +24,4 @@ Check that `AC Charge Start Time 1` and `AC Charge End Time 1` are `00:00` and `
This means that AC Charging can be used between 00:00 and 23:59 (ie, any time of day).
Time 2 and Time 3 can be left as they are, unless you specifically want more specific time ranges setting.
Time 2 and Time 3 can be left as they are, unless you specifically want more specific time ranges setting.

View File

@ -2,7 +2,7 @@
`server.rb` can be configured to connect to an MQTT server. For this, add a section to your `config.ini` like so;
``` ini
```ini
[mqtt]
# see https://github.com/mqtt/mqtt.github.io/wiki/URI-Scheme for URI help
uri = mqtt://server:1883
@ -14,24 +14,25 @@ You can use mqtts for secure connections and add username/password; see the URL
As mentioned in the README, the inverter sends power data (also called inputs) when it feels like it. This is every 2 minutes.
It's sent by the inverter as 3 packets in sequence, around a second apart. When we receive each one, it is published under the keys `octolux/masterinputs/1`, `octolux/masterinputs/2`, and `octolux/masterinputs/3`. Note that the Slave inverter will send iunder the keys `octolux/slaveinputs/1`, `octolux/slaveinputs/2`, and `octolux/slaveinputs/3`. Each one always has the same set of data, and it should look something like this:
It's sent by the inverter as 3 packets in sequence, around a second apart. When we receive each one, it is published under the keys `octolux/inputs/1`, `octolux/inputs/2`, and `octolux/inputs/3`. Each one always has the same set of data, and it should look something like this:
```
$ mosquitto_sub -t octolux/inputs/+ -v
octolux/masterinputs/1 {"status":32,"v_bat":49.4,"soc":53,"p_pv":550,"p_charge":114,"p_discharge":0,"v_acr":247.3,"f_ac":49.96,"p_inv":0,"p_rec":116,"v_eps":247.3,"f_eps":49.96,"p_to_grid":0,"p_to_user":0,"e_pv_day":0.7,"e_inv_day":2.0,"e_rec_day":1.7,"e_chg_day":1.9,"e_dischg_day":2.4,"e_eps_day":0.0,"e_to_grid_day":0.0,"e_to_user_day":3.9,"v_bus_1":379.9,"v_bus_2":300.5}
octolux/masterinputs/2 {"e_pv_all":1675.6,"e_inv_all":943.9,"e_rec_all":1099.3,"e_chg_all":1251.2,"e_dischg_all":1151.6,"e_eps_all":0.0,"e_to_grid_all":124.0,"e_to_user_all":1115.8,"t_inner":43,"t_rad_1":30,"t_rad_2":30}
octolux/masterinputs/3 {"max_chg_curr":105.0,"max_dischg_curr":150.0,"charge_volt_ref":53.2,"dischg_cut_volt":40.0,"bat_status_0":0,"bat_status_1":0,"bat_status_2":0,"bat_status_3":0,"bat_status_4":0,"bat_status_5":192,"bat_status_6":0,"bat_status_7":0,"bat_status_8":0,"bat_status_9":0,"bat_status_inv":3}
octolux/inputs/1 {"status":32,"v_bat":49.4,"soc":53,"p_pv":550,"p_charge":114,"p_discharge":0,"v_acr":247.3,"f_ac":49.96,"p_inv":0,"p_rec":116,"v_eps":247.3,"f_eps":49.96,"p_to_grid":0,"p_to_user":0,"e_pv_day":0.7,"e_inv_day":2.0,"e_rec_day":1.7,"e_chg_day":1.9,"e_dischg_day":2.4,"e_eps_day":0.0,"e_to_grid_day":0.0,"e_to_user_day":3.9,"v_bus_1":379.9,"v_bus_2":300.5}
octolux/inputs/2 {"e_pv_all":1675.6,"e_inv_all":943.9,"e_rec_all":1099.3,"e_chg_all":1251.2,"e_dischg_all":1151.6,"e_eps_all":0.0,"e_to_grid_all":124.0,"e_to_user_all":1115.8,"t_inner":43,"t_rad_1":30,"t_rad_2":30}
octolux/inputs/3 {"max_chg_curr":105.0,"max_dischg_curr":150.0,"charge_volt_ref":53.2,"dischg_cut_volt":40.0,"bat_status_0":0,"bat_status_1":0,"bat_status_2":0,"bat_status_3":0,"bat_status_4":0,"bat_status_5":192,"bat_status_6":0,"bat_status_7":0,"bat_status_8":0,"bat_status_9":0,"bat_status_inv":3}
```
Documenting all these is beyond the scope of this document, but broadly speaking:
* `status` is 0 when idle, 16 when discharging (`p_dischg > 0`), 32 when charging (`p_charge > 0`)
* `v_bat is battery voltage, ` soc`is state-of-charge in %.`v\_bus\` are internal bus voltages
* those prefixed with `p_` are intantaneous power in watts
* `e_` are energy accumulators in `kWh` (and they're present for both today and all-time)
* `f_` are mains Hz
* `t_` are temperatures in celsius; internally, and both radiators on the back of the inverter
* not really worked out what all the `bat_status_` are yet as they're usually mostly 0
* `status` is 0 when idle, 16 when discharging (`p_dischg > 0`), 32 when charging (`p_charge > 0`)
* `v_bat is battery voltage, `soc` is state-of-charge in %. `v_bus` are internal bus voltages
* those prefixed with `p_` are intantaneous power in watts
* `e_` are energy accumulators in `kWh` (and they're present for both today and all-time)
* `f_` are mains Hz
* `t_` are temperatures in celsius; internally, and both radiators on the back of the inverter
* not really worked out what all the `bat_status_` are yet as they're usually mostly 0
You can also request this information to be sent immediately with `octolux/cmd/read_input`, with a payload of 1, 2 or 3, depending on which set of inputs you want:
@ -39,14 +40,8 @@ You can also request this information to be sent immediately with `octolux/cmd/r
$ mosquitto_pub -t octolux/cmd/read_input -m 1
```
This will prompt a further MQ message of `octolux/masterinputs/1` (as above), and additionally `octolux/result/read_input` will be sent with `OK` when it's complete.
This will prompt a further MQ message of `octolux/inputs/1` (as above), and additionally `octolux/result/read_input` will be sent with `OK` when it's complete.
Note for parallel inverters you need to do some post-processing. The SOC values need to be averaged to get the agrigated battery SOC. All the other values need to be summed together.
To match the Lux monitoring web-app you need to do slightly more.
`House Consumption is a sum of p_inv, p_to_user and p_pv of both inverters.`
`p_to_user is the direct import from the grid.`
## Controlling the Inverter
@ -54,10 +49,12 @@ To match the Lux monitoring web-app you need to do slightly more.
In the following, "boolean" can be any of the following to mean true: `1`, `t`, `true`, `y`, `yes`, `on`. Anything else is interpreted as false.
* `octolux/cmd/ac_charge` \- send this a boolean to enable or disable AC charging\. This is taking energy from the grid to charge; this does not need to be on to charge from solar\.
* `octolux/cmd/forced_discharge` \- send this a boolean to enable or disable forced discharging\. This is only useful if you get paid for export and the export rate is high\. Normally\, this should be off; this is *not* related to normal discharging operation.
* `octolux/cmd/discharge_pct` \- send this an integer \(0\-100\) to set the discharge rate\. Normally this is 100% to enable normal discharge\. If you have another cheap electricity source and want the inverter to stop supplying electricity\, setting this to 0 will do that\.
* `octolux/cmd/charge_pct` \- send this an integer \(0\-100\) to set the charge rate\. This probably isn't terribly useful\, but if you want to limit AC charging to less than the full 3600W\, use this to do it\.
* `octolux/cmd/ac_charge` - send this a boolean to enable or disable AC charging. This is taking energy from the grid to charge; this does not need to be on to charge from solar.
* `octolux/cmd/forced_discharge` - send this a boolean to enable or disable forced discharging. This is only useful if you get paid for export and the export rate is high. Normally, this should be off; this is *not* related to normal discharging operation.
* `octolux/cmd/discharge_pct` - send this an integer (0-100) to set the discharge rate. Normally this is 100% to enable normal discharge. If you have another cheap electricity source and want the inverter to stop supplying electricity, setting this to 0 will do that.
* `octolux/cmd/charge_pct` - send this an integer (0-100) to set the charge rate. This probably isn't terribly useful, but if you want to limit AC charging to less than the full 3600W, use this to do it.
* `octolux/cmd/charge_amount_pct` - send this an integer (0-100) to set the charge level limit when AC charging; eg to only AC Charge up to 50%, set 50.
So for example, you could do;
@ -77,7 +74,7 @@ This is quite low-level and may not be terribly useful yet; this is subject to i
The inverter has a bunch of registers that determine current operation. There's a full list in my [lxp-packet](https://github.com/celsworth/lxp-packet/blob/master/doc/LXP_REGISTERS.txt) gem.
So for example, setting discharge percentage is register 65 (DISCHG\_POWER\_PERCENT\_CMD from the register list).
So for example, setting discharge percentage is register 65 (DISCHG_POWER_PERCENT_CMD from the register list).
So if I send:
@ -104,4 +101,4 @@ Finally, if you know the register you want and want it on-demand, you can send `
$ mosquitto_pub -t octolux/cmd/read_hold -m 65
```
This will result in `octolux/hold/65` being sent (as above) and additionally `octolux/result/read_hold` will be sent (with `OK`) once complete.
This will result in `octolux/hold/65` being sent (as above) and additionally `octolux/result/read_hold` will be sent (with `OK`) once complete.

View File

@ -1,34 +1,18 @@
[lxp]
host = 192.168.3.240
host = 192.168.0.200
port = 8000
serial = *0252016062
datalog = BA10330137
host_slave = 192.168.3.241
port_slave = 8000
serial_slave = *0252016063
datalog_slave = BA10330178
batteries = 2
serial = 9393013580
datalog = EF76460231
batteries = 4
# these can be obtained from your Octopus account;
# see the URL under Unit Rates at https://octopus.energy/dashboard/developer/
#
# note that the tariff_code has a different final letter depending
# on your region, so unless you're in North West England you may need to change this.
# on your region, so unless you're in West Midlands you may need to change this.
[octopus]
product_code = AGILE-18-02-21
tariff_code = E-1R-AGILE-18-02-21-G
# These are found from your Solcast Account
[solcast]
api_key = abcdefghijklmnopqrstuvwxyz123456
resource_id = abcd-1234-efgh
# Enter your house baseload here (in watts) to calculate excess solar.
base_load = 300
# Enter the maximum age (in minutes) Solcast should be before refreshing
# Every slot < 30. Cronjob limits to every 30. [50 queries per day in free tier]
max_forecast_age = 25
tariff_code = E-1R-AGILE-18-02-21-E
[server]
# used by server.rb to open a listening port.
@ -42,20 +26,15 @@ port = 4346
# see https://github.com/mqtt/mqtt.github.io/wiki/URI-Scheme for URI help
# you can leave this commented out if you don't want to use MQTT at all.
# uri = mqtt://nas:1883
# uri = mqtt://emonpi:emonpimqtt2016@emonpi:1883
[rules]
# use the cheapest energy to get the batteries to this SOC each night
required_soc = 90
# enable emergency charge if approaching peak period with less SOC than this.
# this is a final backup to avoid running out of charge during peak
emergency_soc = 35
emergency_soc = 50
# always charge when electricity is cheaper than this unit price,
# even if the SOC is already higher than required_soc
cheap_charge = 2
# never charge when electricity is more expensive than this unit price
max_charge = 9
# Prior to peak period, never discharge is price is cheaper than this unit price
pre_discharge = 12
# After the peak period, never discharge if price is cheaper than this unit price
post_discharge = 10
# never discharge when electricity is cheaper than this unit price
min_discharge = 3

View File

@ -7,8 +7,7 @@ LOGGER.info "Current Octopus Unit Price: #{octopus.price}p"
# $lc is LuxController. This talks directly to the inverter and can do things
# like enabling/disabling AC charge and setting charge power rates.
# LOGGER.info "Charge Power = #{lc-mast.charge_pct}%"
# LOGGER.info "Charge Power = #{lc-slave.charge_pct}%"
# LOGGER.info "Charge Power = #{lc.charge_pct}%"
# $ls is LuxStatus. This is gleaned from the optional server.rb since the
# data in it is only sent by the inverter every 2 minutes.
@ -19,13 +18,8 @@ begin
# if the current price is 5p or lower, enable AC charge
charge = octopus.price <= 5
unless lc-mast.charge(charge)
LOGGER.error 'Failed to update master inverter status :-('
exit 255
end
unless lc-slave.charge(charge)
LOGGER.error 'Failed to update slave inverter status :-('
unless lc.charge(charge)
LOGGER.error 'Failed to update inverter status!'
exit 255
end
rescue StandardError => e

View File

@ -94,7 +94,7 @@ end
LOGGER.info "ac_charge = #{ac_charge} ; discharge = #{discharge} (> #{min_discharge_price}p)"
discharge_pct = discharge ? 100 : 0
r-mast = (lc-mast.discharge_pct = discharge_pct)
exit 255 unless r-mast == discharge_pct
r = (lc.discharge_pct = discharge_pct)
exit 255 unless r == discharge_pct
exit 255 unless lc-mast.charge(ac_charge)
exit 255 unless lc.charge(ac_charge)

View File

@ -14,4 +14,4 @@ class IniFile
end
end
end
end
end

View File

@ -8,10 +8,6 @@ class LuxController
def initialize(host:, port:, serial:, datalog:)
@host = host
@port = port
#####################
# Line to remove first character from the inverter serial number - this is a work around to ensure Serial number is read correctly as the Ruby Gems IniFile package seems to incorrectly type cast a serial number starting with a 0
serial[0] = ''
#####################
# these can be numeric, but we want them as strings to put into data packets
@serial = serial.to_s
@datalog = datalog.to_s
@ -23,7 +19,7 @@ class LuxController
end
def read_input(num)
LOGGER.info "read_input(#{num})"
LOGGER.debug "read_input(#{num})"
type = case num
when 1 then LXP::Packet::ReadInput1
@ -72,6 +68,16 @@ class LuxController
set_register(LXP::Packet::Registers::DISCHG_POWER_PERCENT_CMD, pct)
end
# Untested - get current charge amount %
def charge_amount_pct
read_register(LXP::Packet::Registers::AC_CHARGE_SOC_LIMIT)
end
# Untested - set current charge amount %
def charge_amount_pct=(pct)
set_register(LXP::Packet::Registers::AC_CHARGE_SOC_LIMIT, pct)
end
private
# Update a given register (21 for AC CHARGE/DISCHARGE) with the given bit
@ -80,12 +86,12 @@ class LuxController
# Returns true if the bit was already as requested, or updated.
#
def update_register(register, bit, enable)
LOGGER.info "update_register(#{register}, #{bit}, #{enable})"
LOGGER.debug "update_register(#{register}, #{bit}, #{enable})"
old_val = read_register(register)
enabled = (old_val & bit) == bit
if enable == enabled
LOGGER.info "update_register(#{register}) => no action required"
LOGGER.debug "update_register(#{register}) => no action required"
return true
end
@ -96,18 +102,18 @@ class LuxController
end
def read_register(register)
LOGGER.info "read_register(#{register})"
LOGGER.debug "read_register(#{register})"
pkt = packet(type: LXP::Packet::ReadHold, register: register)
socket.write(pkt)
r = read_reply(pkt)
LOGGER.info "read_register(#{register}) => #{r.value}"
LOGGER.debug "read_register(#{register}) => #{r.value}"
r.value
end
def set_register(register, val)
LOGGER.info "set_register(#{register}, #{val})"
LOGGER.debug "set_register(#{register}, #{val})"
pkt = packet(type: LXP::Packet::WriteSingle, register: register)
pkt.value = val
@ -115,7 +121,7 @@ class LuxController
socket.write(pkt)
r = read_reply(pkt)
LOGGER.info "set_register(#{register}) => #{r.value}"
LOGGER.debug "set_register(#{register}) => #{r.value}"
r.value
end
@ -134,7 +140,7 @@ class LuxController
def read_reply(pkt)
unless (r = socket.read_reply(pkt))
LOGGER.fatal 'Invalid/no reply from inverter'
LOGGER.fatal 'invalid/no reply from inverter'
raise SocketError
end

View File

@ -4,8 +4,8 @@ $LOAD_PATH.unshift 'lib'
require 'lxp/packet'
#require 'socket'
require 'json'
require 'roda'
#require 'json'
#require 'roda'
#require 'inifile'
# This starts in a thread and watches for incoming traffic from the inverter.
@ -22,23 +22,23 @@ class LuxListener
loop do
socket = LuxSocket.new(host: host, port: port)
if @slave == 0
LOGGER.info("Created new Master LuxListener")
LOGGER.info("lux_listener- Created new Master LuxListener")
else
LOGGER.info("Created new Slave LuxListener")
LOGGER.info("lux_listener- Created new Slave LuxListener")
end
listen(socket, slave)
rescue StandardError => e
if @slave == 0
LOGGER.error "Socket Master Error: #{e}"
LOGGER.error "lux_listener- Socket Master Error: #{e}"
else
LOGGER.error "Socket Slave Error: #{e}"
LOGGER.error "lux_listener- Socket Slave Error: #{e}"
end
LOGGER.debug e.backtrace.join("\n")
if @slave == 0
LOGGER.info 'Reconnecting to Master in 5 seconds'
LOGGER.info 'lux_listener- Reconnecting to Master in 5 seconds'
else
LOGGER.info 'Reconnecting to Slave in 5 seconds'
LOGGER.info 'lux_listener- Reconnecting to Slave in 5 seconds'
end
sleep 5
end
@ -70,35 +70,13 @@ class LuxListener
end
def process_input(pkt, slave)
# Construct a temporary json file to store inverter data
LOGGER.info("process_input: Creating json files")
if @slave == 0
# json_file = "~/lxp_datamaster.json"
else
# json_file = "~/lxp_dataslave.json"
end
output = Hash.new # setup scope
inputs.merge!(pkt.to_h)
LOGGER.info pkt
n = case pkt
when LXP::Packet::ReadInput1 then 1
# first packet starts a new hash
output = pkt.to_h
#JSON_DATA.replace(JSON.generate(output))
#File.write(JSON_FILE, JSON_DATA)
when LXP::Packet::ReadInput2 then 2
# second packet merges in
output.merge!(pkt.to_h)
#JSON_DATA.replace(JSON.generate(output))
#File.write(JSON_FILE, JSON_DATA)
when LXP::Packet::ReadInput3 then 3
# final packet merges in and saves the result
output.merge!(pkt.to_h)
JSON_DATA.replace(JSON.generate(output))
File.write(JSON_FILE, JSON_DATA)
end
end
# Not very neat... but it allows us to see both inverters separately.
if slave == 0
@ -106,10 +84,6 @@ class LuxListener
else
MQ.publish("octolux/slaveinputs/#{n}", pkt.to_h, slave)
end
LOGGER.info("process_input: Writing json files")
File.write(JSON_FILE, JSON_DATA)
LOGGER.info JSON_FILE
LOGGER.info JSON_DATA
end
def process_read_hold(pkt, slave)

View File

@ -13,6 +13,8 @@ class MQ
sub.subscribe_to 'octolux/cmd/charge_pct', &method(:charge_pct_cb)
sub.subscribe_to 'octolux/cmd/discharge_pct', &method(:discharge_pct_cb)
sub.subscribe_to 'octolux/cmd/charge_amount_pct', &method(:charge_amount_pct_cb)
Thread.stop # sleep forever
end
@ -107,6 +109,20 @@ class MQ
sub.publish_to('octolux/result/discharge_pct', 'FAIL')
end
def charge_amount_pct_cb(data, *)
LOGGER.info "MQ cmd/charge_amount_pct => #{data}"
if @slave == 0
r = (lux_controller.charge_amount_pct = data.to_i)
lux_controller.close
else
r = (lux_controller.charge_amount_pct = data.to_i)
lux_controller.close
end
sub.publish_to('octolux/result/charge_amount_pct', r == data.to_i ? 'OK' : 'FAIL')
rescue LuxController::SocketError
sub.publish_to('octolux/result/charge_amount_pct', 'FAIL')
end
def uri
CONFIG['mqtt']['uri']
end
@ -126,7 +142,7 @@ class MQ
port: CONFIG['lxp']['port_slave'],
serial: CONFIG['lxp']['serial_slave'],
datalog: CONFIG['lxp']['datalog_slave'])
end
end
def bool(input)
case input

View File

@ -1,33 +1,3 @@
Skip to content
Search or jump to
Pull requests
Issues
Marketplace
Explore
@AndyWhittaker
m1geo
/
octolux
forked from biohead/octolux
1
110
Code
Pull requests
Actions
Projects
Security
Insights
octolux/lib/solcast.rb /
@m1geo
m1geo Some bug fixes between Ruby versions
Latest commit 52c7e6f 3 days ago
History
2 contributors
@m1geo@celsworth
107 lines (89 sloc) 2.54 KB
# frozen_string_literal: true
require 'pathname'

View File

@ -1,48 +1,49 @@
#! /usr/bin/env ruby
# frozen_string_literal: true
require 'time'
require_relative 'boot'
solcast = Solcast.new(api_key: CONFIG['solcast']['api_key'],
resource_id: CONFIG['solcast']['resource_id'])
solcast_slate = solcast.stale(CONFIG['solcast']['max_forecast_age'])
solcast_valid_updating_window = Time.now.hour < 22 # true if update allowed - time as per machine time
solcast_updated = (solcast_slate and solcast_valid_updating_window)
#LOGGER.debug "Solcast valid window = #{solcast_valid_updating_window}"
#LOGGER.debug "Solcast stale data = #{solcast_slate}"
solcast.update if solcast_updated
LOGGER.info "Solcast data updated = #{solcast_updated}"
octopus = Octopus.new(product_code: CONFIG['octopus']['product_code'],
tariff_code: CONFIG['octopus']['tariff_code'])
# if we have less than 6 hours of future $octopus tariff data, update it
octopus.update if octopus.stale?
unless octopus.price
LOGGER.fatal 'No current Octopus price, aborting'
exit 255
end
# rubocop:disable Lint/UselessAssignment
# FIXME: duplicated in mq.rb, could move to boot.rb?
lc = LuxController.new(host: CONFIG['lxp']['host'],
port: CONFIG['lxp']['port'],
serial: CONFIG['lxp']['serial'],
datalog: CONFIG['lxp']['datalog'])
# This is for the secondary (slave) inverter
lc_slave = LuxController.new(host: CONFIG['lxp']['host_slave'],
port: CONFIG['lxp']['port_slave'],
serial: CONFIG['lxp']['serial_slave'],
datalog: CONFIG['lxp']['datalog_slave'])
ls = LuxStatus.new(host: CONFIG['server']['connect_host'] || CONFIG['server']['host'],
port: CONFIG['server']['port'])
# rubocop:enable Lint/UselessAssignment
raise('rules.rb not found!') unless File.readable?('rules.rb')
instance_eval(File.read('rules.rb'), 'rules.rb')
#! /usr/bin/env ruby
# frozen_string_literal: true
require 'time'
require_relative 'boot'
solcast = Solcast.new(api_key: CONFIG['solcast']['api_key'],
resource_id: CONFIG['solcast']['resource_id'])
solcast_slate = solcast.stale(CONFIG['solcast']['max_forecast_age'])
solcast_valid_updating_window = Time.now.hour < 22 # true if update allowed - time as per machine time
solcast_updated = (solcast_slate and solcast_valid_updating_window)
#LOGGER.debug "Solcast valid window = #{solcast_valid_updating_window}"
#LOGGER.debug "Solcast stale data = #{solcast_slate}"
solcast.update if solcast_updated
LOGGER.info "Solcast data updated = #{solcast_updated}"
octopus = Octopus.new(product_code: CONFIG['octopus']['product_code'],
tariff_code: CONFIG['octopus']['tariff_code'])
# if we have less than 6 hours of future $octopus tariff data, update it
octopus.update if octopus.stale?
unless octopus.price
LOGGER.fatal 'No current Octopus price, aborting'
exit 255
end
# rubocop:disable Lint/UselessAssignment
# FIXME: duplicated in mq.rb, could move to boot.rb?
lc = LuxController.new(host: CONFIG['lxp']['host'],
port: CONFIG['lxp']['port'],
serial: CONFIG['lxp']['serial'],
datalog: CONFIG['lxp']['datalog'])
# This is for the secondary (slave) inverter
lc_slave = LuxController.new(host: CONFIG['lxp']['host_slave'],
port: CONFIG['lxp']['port_slave'],
serial: CONFIG['lxp']['serial_slave'],
datalog: CONFIG['lxp']['datalog_slave'])
# used by server.rb to open a listening port.
ls = LuxStatus.new(host: CONFIG['server']['connect_host'] || CONFIG['server']['host'],
port: CONFIG['server']['port'])
# rubocop:enable Lint/UselessAssignment
raise('rules.rb not found!') unless File.readable?('rules.rb')
instance_eval(File.read('rules.rb'), 'rules.rb')

View File

@ -19,15 +19,15 @@ Thread.new do
loop do
t = Thread.new do
begin
LOGGER.info("Creating new Master LuxListener")
LOGGER.info("server- Creating new Master LuxListener")
LuxListener.run(host: CONFIG['lxp']['host'], port: CONFIG['lxp']['port'], slave: 0)
rescue StandardError => e
LOGGER.error "LuxListener Master Thread: #{e}"
LOGGER.error "server- LuxListener Master Thread: #{e}"
LOGGER.debug e.backtrace.join("\n")
end
end
t.join
LOGGER.info 'Restarting Master LuxListener Thread in 5 seconds'
LOGGER.info 'server- Restarting Master LuxListener Thread in 5 seconds'
sleep 5
end
end
@ -37,15 +37,15 @@ Thread.new do
loop do
tslave = Thread.new do
begin
LOGGER.info("Creating new Slave LuxListener")
LOGGER.info("server- Creating new Slave LuxListener")
LuxListener.run(host: CONFIG['lxp']['host_slave'], port: CONFIG['lxp']['port_slave'], slave: 1)
rescue StandardError => e
LOGGER.error "LuxListener Slave Thread: #{e}"
LOGGER.error "server- LuxListener Slave Thread: #{e}"
LOGGER.debug e.backtrace.join("\n")
end
end
tslave.join
LOGGER.info 'Restarting Slave LuxListener Thread in 5 seconds'
LOGGER.info 'server- Restarting Slave LuxListener Thread in 5 seconds'
sleep 5
end
end