Skip to content

Commit

Permalink
Merge branch 'release/0.4.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
ledermann committed Aug 22, 2024
2 parents f1d1353 + d84cc68 commit d27c99e
Show file tree
Hide file tree
Showing 12 changed files with 370 additions and 29 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
run: bundle exec rspec

- name: Send test coverage to CodeClimate
uses: paambaati/codeclimate-action@v8.0.0
uses: paambaati/codeclimate-action@v9.0.0
if: ${{ env.CC_TEST_REPORTER_ID }}
with:
coverageCommand: true
Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ gem 'csv'
gem 'base64'

# A toolkit of support libraries and Ruby core extensions extracted from the Rails framework. (https://rubyonrails.org)
gem 'activesupport'
gem 'activesupport', '~> 7.1', '< 7.2'

# A Ruby client library for Redis (https://github.com/redis/redis-rb)
gem 'redis'
Expand Down
21 changes: 11 additions & 10 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ GEM
base64 (0.2.0)
bigdecimal (3.1.8)
coderay (1.1.3)
concurrent-ruby (1.3.3)
concurrent-ruby (1.3.4)
connection_pool (2.4.1)
crack (1.0.0)
bigdecimal
Expand Down Expand Up @@ -55,14 +55,14 @@ GEM
rb-inotify (~> 0.9, >= 0.9.10)
lumberjack (1.2.10)
method_source (1.1.0)
minitest (5.24.1)
minitest (5.25.1)
mutex_m (0.2.0)
nenv (0.3.0)
notiffany (0.1.3)
nenv (~> 0.1)
shellany (~> 0.0)
parallel (1.25.1)
parser (3.3.4.0)
parallel (1.26.3)
parser (3.3.4.2)
ast (~> 2.4.1)
racc
pry (0.14.2)
Expand All @@ -75,20 +75,20 @@ GEM
rb-fsevent (0.11.2)
rb-inotify (0.11.1)
ffi (~> 1.0)
redis (5.2.0)
redis (5.3.0)
redis-client (>= 0.22.0)
redis-client (0.22.2)
connection_pool
regexp_parser (2.9.2)
rexml (3.3.4)
rexml (3.3.6)
strscan
rspec (3.13.0)
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.0)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.1)
rspec-expectations (3.13.2)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.1)
Expand All @@ -106,7 +106,7 @@ GEM
rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.32.0)
rubocop-ast (1.32.1)
parser (>= 3.3.1.0)
rubocop-performance (1.21.1)
rubocop (>= 1.48.1, < 2.0)
Expand All @@ -130,7 +130,8 @@ GEM
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.5.0)
vcr (6.2.0)
vcr (6.3.1)
base64
webmock (3.23.1)
addressable (>= 2.8.0)
crack (>= 0.3.2)
Expand All @@ -140,7 +141,7 @@ PLATFORMS
ruby

DEPENDENCIES
activesupport
activesupport (~> 7.1, < 7.2)
amazing_print
base64
csv
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ This enables SOLECTRUS to accurately calculate the electricity usage and costs f

The Docker image supports multiple platforms: `linux/amd64`, `linux/arm64`

To force a data rebuild, you can delete the measurement from the InfluxDB database:
To force a data rebuild, you can send USR1 signal to the container:

```bash
influx delete --bucket ${INFLUX_BUCKET} --start '1970-01-01T00:00:00Z' --stop $(date -u +"%Y-%m-%dT%H:%M:%SZ") --predicate '_measurement="power_splitter"' --org ${INFLUX_ORG} --token ${INFLUX_TOKEN}
docker compose kill --signal USR1 power-splitter
```

## Development
Expand Down
2 changes: 1 addition & 1 deletion app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

logger = StdoutLogger.new

buildtime = ENV.fetch('BUILDTIME', nil)
buildtime = ENV.fetch('BUILDTIME', nil).presence
buildtime = buildtime ? Time.parse(buildtime).localtime : '<unknown>'

logger.info 'Power Splitter for SOLECTRUS, ' \
Expand Down
67 changes: 60 additions & 7 deletions lib/loop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,72 @@
require 'redis_cache'

class Loop
def initialize(config:)
def initialize(config:, max_count: nil)
@config = config
@max_count = max_count
end

attr_reader :config
attr_reader :config, :thread, :restarting, :max_count

def start
# config.logger.info "--- Deleting all records from InfluxDB measurement '#{config.influx_measurement}'"
# influx_push.delete_measurement(config.influx_measurement)
# config.logger.info " Ok, deleted sucessfully\n\n"
Signal.trap('USR1') { restart }

process_historical_data
process_current_data
loop do
start_thread

# There are two reasons we get here:
# 1. The thread finished accidentally, so we should stop by breaking the loop.
# 2. We received a USR1 signal and should restart.
break unless restarting

# Restart requsted, so delete all data and loop again.
delete_all
@restarting = false
end
rescue SystemExit, Interrupt
config.logger.warn 'Exiting...'
end

def restart
unless thread
config.logger.warn "\n--- No thread to restart..."
return
end

config.logger.info "\n--- Restarting..."
@restarting = true

# Terminate the thread
thread.exit

# Wait for the thread to finish
timeout = Time.current + 5
sleep(1) while thread.alive? && Time.current < timeout

if thread.alive?
config.logger.warn 'Thread did not finish in time.'
thread.kill
config.logger.warn 'Thread killed.'
else
config.logger.info 'Thread exited cleanly.'
end
end

private

def start_thread
@thread =
Thread.new do # rubocop:disable ThreadSafety/NewThread
process_historical_data
process_current_data
end
thread.join
end

def process_current_data
config.logger.info "\nStarting endless loop for processing current data..."

count = 0
last_time = nil
loop do
# Ensure that the last minutes of yesterday are processed
Expand All @@ -37,6 +81,9 @@ def process_current_data
last_time = Time.current
process_day(Date.current)

count += 1
break if max_count && count >= max_count

config.logger.info " Sleeping for #{config.influx_interval} seconds...\n\n"
sleep(config.influx_interval)
end
Expand Down Expand Up @@ -69,6 +116,12 @@ def process_day(day)
influx_push.push(splitted_powers)
end

def delete_all
config.logger.info "\n--- Deleting all records from InfluxDB measurement '#{config.influx_measurement}'"
influx_push.delete_measurement(config.influx_measurement)
config.logger.info " Ok, deleted sucessfully\n\n"
end

def influx_push
@influx_push ||= InfluxPush.new(config:)
end
Expand Down
10 changes: 5 additions & 5 deletions lib/processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def initialize(day_records:, config:)
attr_reader :day_records, :config, :wallbox_present, :heatpump_present

def call
group_by_hour(
group_by_5min(
day_records.reduce([]) { |acc, elem| acc << split_power(elem) },
).map { |elem| point(elem) }
end
Expand All @@ -40,12 +40,12 @@ def point(record)
result
end

def group_by_hour(splitted)
def group_by_5min(splitted)
splitted
.group_by { |item| item[:time].hour }
.map do |_hour, items|
.group_by { |item| (item[:time].to_i - 1.minute) / 5.minutes }
.map do |_interval, items|
{
time: items.first[:time].beginning_of_hour,
time: items.first[:time].beginning_of_minute,
house_power_grid: sum(items, :house_power_grid),
wallbox_power_grid:
wallbox_present ? sum(items, :wallbox_power_grid) : nil,
Expand Down
2 changes: 2 additions & 0 deletions lib/splitter/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ def initialize(
:heatpump_power

def call
#:nocov:
raise NotImplementedError
#:nocov:
end

private
Expand Down
129 changes: 129 additions & 0 deletions spec/cassettes/loop-restart.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit d27c99e

Please sign in to comment.