Skip to content

Commit

Permalink
Add Cloud support
Browse files Browse the repository at this point in the history
Includes lots of refactoring
No more need of SHELLY_GEN
  • Loading branch information
ledermann committed Jan 16, 2025
1 parent 9d0d0d3 commit cba8372
Show file tree
Hide file tree
Showing 26 changed files with 830 additions and 584 deletions.
3 changes: 0 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# IP of your Shelly device
SHELLY_HOST=192.168.1.1

# Generation of your Shelly device (1 or 2 or 3, default is 2)
SHELLY_GEN=2

# Interval in seconds to get data from Shelly
SHELLY_INTERVAL=5

Expand Down
1 change: 1 addition & 0 deletions .env.test
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
SHELLY_CLOUD_SERVER=https://shelly-95-eu.shelly.cloud
SHELLY_HOST=shelly-pro-3em
SHELLY_INTERVAL=5

Expand Down
33 changes: 15 additions & 18 deletions lib/config.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
require 'shelly_gen1_adapter'
require 'shelly_gen2_adapter'
require 'shelly_gen3_adapter'
require 'shelly_local_adapter'
require 'shelly_cloud_adapter'
require 'blank'
require 'null_logger'

KEYS = %i[
shelly_host
shelly_gen
shelly_cloud_server
shelly_device_id
shelly_auth_key
shelly_interval
influx_schema
influx_host
Expand All @@ -19,7 +20,6 @@
].freeze

DEFAULTS = {
shelly_gen: 2,
shelly_interval: 5,
influx_schema: :http,
influx_port: 8086,
Expand Down Expand Up @@ -54,7 +54,7 @@ def convert_types
end

# Integer
%i[shelly_interval influx_port shelly_gen].each do |key|
%i[shelly_interval influx_port].each do |key|
self[key] = self[key]&.to_i
end
end
Expand All @@ -74,20 +74,19 @@ def limit_interval
def validate!
validate_influx_settings!
validate_interval!(shelly_interval)
validate_gen!(shelly_gen)
end

def influx_url
"#{influx_schema}://#{influx_host}:#{influx_port}"
end

def shelly_url
"http://#{shelly_host}"
end

def adapter
# Instance of ShellyGen1Adapter, ShellyGen2Adapter, or ShellyGen3Adapter
@adapter ||= Object.const_get("ShellyGen#{shelly_gen}Adapter").new(config: self)
@adapter ||=
if shelly_cloud_server
ShellyCloudAdapter.new(config: self)
else
ShellyLocalAdapter.new(config: self)
end
end

attr_writer :logger
Expand All @@ -102,10 +101,6 @@ def validate_interval!(interval)
(interval.is_a?(Integer) && interval.positive?) || throw("SHELLY_INTERVAL is invalid: #{interval}")
end

def validate_gen!(gen)
[1, 2, 3].include?(gen) || throw("SHELLY_GEN is invalid: #{gen}")
end

def validate_influx_settings!
%i[
influx_schema
Expand Down Expand Up @@ -137,7 +132,9 @@ def self.from_env(options = {})
new(
{
shelly_host: ENV.fetch('SHELLY_HOST', nil),
shelly_gen: ENV.fetch('SHELLY_GEN', nil),
shelly_cloud_server: ENV.fetch('SHELLY_CLOUD_SERVER', nil),
shelly_device_id: ENV.fetch('SHELLY_DEVICE_ID', nil),
shelly_auth_key: ENV.fetch('SHELLY_AUTH_KEY', nil),
shelly_interval: ENV.fetch('SHELLY_INTERVAL', nil),
influx_host: ENV.fetch('INFLUX_HOST'),
influx_schema: ENV.fetch('INFLUX_SCHEMA', nil),
Expand Down
69 changes: 69 additions & 0 deletions lib/shelly_cloud_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
require 'solectrus_record'
require 'forwardable'
require 'faraday'
require 'faraday-request-timer'

class ShellyCloudAdapter
extend Forwardable
def_delegators :config, :logger

def initialize(config:)
@config = config

logger.info "Pulling from Shelly (Cloud) for device #{config.shelly_device_id} every #{config.shelly_interval} seconds"
end

attr_reader :config

def connection
@connection ||= Faraday.new(url: config.shelly_cloud_server) do |f|
f.adapter Faraday.default_adapter
f.request :timer
end
end

def solectrus_record(id = 1)
# Reset cache
@data = nil
@raw_response = nil

parser = ShellyResponseParser.new(raw_response.body)
record = parser.solectrus_record(id:, response_duration:)
logger.info success_message(record)
record
rescue StandardError => e
logger.error failure_message(e)
nil
end

private

def raw_response
@raw_response ||= begin
response = connection.get('/device/status') do |req|
req.params['id'] = config.shelly_device_id
req.params['auth_key'] = config.shelly_auth_key
end

raise StandardError, response.status unless response.success?

response
end
end

def success_message(record)
"\nGot record ##{record.id} at " \
"#{Time.at(record.time).localtime} " \
"within #{record.response_duration} ms, " \
"Power #{record.power.round(1)} W, " \
"Temperature #{record.temp} °C"
end

def failure_message(error)
"Error getting data from Shelly at #{config.shelly_host}: #{error}"
end

def response_duration
(raw_response.env[:duration] * 1000).round
end
end
107 changes: 0 additions & 107 deletions lib/shelly_gen2_adapter.rb

This file was deleted.

106 changes: 0 additions & 106 deletions lib/shelly_gen3_adapter.rb

This file was deleted.

Loading

0 comments on commit cba8372

Please sign in to comment.