Skip to content

Commit

Permalink
Merge pull request #56 from emoncms/master
Browse files Browse the repository at this point in the history
Merge master to stable
  • Loading branch information
TrystanLea authored Jul 30, 2020
2 parents d689aae + 9338e5f commit 1eaa3ef
Show file tree
Hide file tree
Showing 8 changed files with 816 additions and 30 deletions.
619 changes: 619 additions & 0 deletions LICENSE.txt

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
"forum": "https://community.openenergymonitor.org/"
},
"require-dev": {
"jakub-onderka/php-parallel-lint": "1.0.0"
"php-parallel-lint/php-parallel-lint": "^1.2.0"
},
"scripts": {
"test": [
"parallel-lint . --exclude vendor"
]
}
},
"license": "AGPL-3.0-or-later"
}
4 changes: 4 additions & 0 deletions demandshaper-module/general.js
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ function load_device(device_id, device_name, device_type)
var sum = 0;
var sum_n = 0;
var peak = 0;
var lowest = 0;
var active = 0;
available = [];
unavailable = [];
Expand All @@ -456,6 +457,7 @@ function load_device(device_id, device_name, device_type)
var value = profile[z][1];

if (value>peak) peak = value;
if (value<lowest) lowest = value;

active = false;
for (var p in periods) {
Expand All @@ -472,6 +474,8 @@ function load_device(device_id, device_name, device_type)
unavailable.push([time,value]);
}

options.yaxis.min = lowest;

// Display CO2 in window
var out = "";
if (sum_n>0) {
Expand Down
2 changes: 1 addition & 1 deletion demandshaper-module/module.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"name" : "DemandShaper",
"version" : "1.2.5"
"version" : "1.2.6"
}
45 changes: 22 additions & 23 deletions demandshaper_run.php
Original file line number Diff line number Diff line change
Expand Up @@ -361,33 +361,32 @@
// -------------------------------------------------------------------
// Recalculate based on car SOC
// -------------------------------------------------------------------
if ($schedule->settings->device_type=="openevse" && (time()-$last_soc_update)>600) {
if ($schedule->settings->device_type=="openevse" && (time()-$last_soc_update)>600 && isset($schedule->settings->openevsecontroltype) && $schedule->settings->openevsecontroltype!='time') {
$last_soc_update = time();
if (isset($schedule->settings->openevsecontroltype)) {
if ($schedule->settings->openevsecontroltype=='socinput') {
if ($feedid = $input->exists_nodeid_name($userid,$device,"soc")) {
$schedule->settings->ev_soc = $input->get_last_value($feedid)*0.01;
$log->error("Recalculating EVSE schedule based on emoncms input: ".$schedule->settings->ev_soc);
}

if ($schedule->settings->openevsecontroltype=='socinput') {
if ($feedid = $input->exists_nodeid_name($userid,$device,"soc")) {
$schedule->settings->ev_soc = $input->get_last_value($feedid)*0.01;
$log->info("Recalculating EVSE schedule based on emoncms input: ".$schedule->settings->ev_soc);
}
else if ($schedule->settings->openevsecontroltype=='socovms') {
if ($schedule->settings->ovms_vehicleid!='' && $schedule->settings->ovms_carpass!='') {
$ovms = $demandshaper->fetch_ovms_v2($schedule->settings->ovms_vehicleid,$schedule->settings->ovms_carpass);
if (isset($ovms['soc'])) $schedule->settings->ev_soc = $ovms['soc']*0.01;
$log->error("Recalculating EVSE schedule based on ovms: ".$schedule->settings->ev_soc);
}
else if ($schedule->settings->openevsecontroltype=='socovms') {
if ($schedule->settings->ovms_vehicleid!='' && $schedule->settings->ovms_carpass!='') {
$ovms = $demandshaper->fetch_ovms_v2($schedule->settings->ovms_vehicleid,$schedule->settings->ovms_carpass);
if (isset($ovms['soc'])) $schedule->settings->ev_soc = $ovms['soc']*0.01;
$log->info("Recalculating EVSE schedule based on ovms: ".$schedule->settings->ev_soc);

}
}
$kwh_required = ($schedule->settings->ev_target_soc-$schedule->settings->ev_soc)*$schedule->settings->batterycapacity;
$schedule->settings->period = $kwh_required/$schedule->settings->chargerate;

if (isset($schedule->settings->balpercentage) && $schedule->settings->balpercentage < $schedule->settings->ev_target_soc) {
$schedule->settings->period += $schedule->settings->baltime;
}

$schedule->runtime->timeleft = $schedule->settings->period * 3600;
$log->error("EVSE timeleft: ".$schedule->runtime->timeleft);
}
$kwh_required = ($schedule->settings->ev_target_soc-$schedule->settings->ev_soc)*$schedule->settings->batterycapacity;
$schedule->settings->period = $kwh_required/$schedule->settings->chargerate;

if (isset($schedule->settings->balpercentage) && $schedule->settings->balpercentage < $schedule->settings->ev_target_soc) {
$schedule->settings->period += $schedule->settings->baltime;
}

$schedule->runtime->timeleft = $schedule->settings->period * 3600;
$log->info("EVSE timeleft: ".$schedule->runtime->timeleft);
}
// -------------------------------------------------------------------

Expand Down Expand Up @@ -458,7 +457,7 @@
try { $mqtt_client->loop(); } catch (Exception $e) { }

// Dont loop to fast
sleep(0.1);
usleep(100000);
}

function connect($r, $message) {
Expand Down
11 changes: 10 additions & 1 deletion emoncms-remote/demandshaper_controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,16 @@ function demandshaper_controller()
if ($route->action == 'carbonintensity') $result = json_decode($redis->get("demandshaper:carbonintensity"));

// "https://api.octopus.energy/v1/products/AGILE-18-02-21/electricity-tariffs/E-1R-AGILE-18-02-21-D/standard-unit-rates/"
else if ($route->action == 'octopus') $result = json_decode($redis->get("demandshaper:octopus"));
else if ($route->action == 'octopus') {
$gsp_id = "D";
if (isset($_GET['gsp'])) {
if (in_array($_GET['gsp'],array("A","B","C","D","E","F","G","H","J","K","L","M","N","P"))) {
$gsp_id = $_GET['gsp'];
}
}

$result = json_decode($redis->get("demandshaper:octopus:$gsp_id"));
}

return array('content'=>$result);
}
92 changes: 89 additions & 3 deletions emoncms_remote_cache.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,44 @@
<?php
// ----------------------------------------------------
// Load emoncms context: mysql, redis and feed model
// ----------------------------------------------------
define('EMONCMS_EXEC', 1);
chdir("/var/www/emoncms");
require "process_settings.php";
require "Lib/EmonLogger.php";

$mysqli = @new mysqli(
$settings["sql"]["server"],
$settings["sql"]["username"],
$settings["sql"]["password"],
$settings["sql"]["database"],
$settings["sql"]["port"]
);
if ( $mysqli->connect_error ) {
$log->error("Can't connect to database, please verify credentials/configuration in settings.php");
if ( $display_errors ) {
$log->error("Error message: ".$mysqli->connect_error);
}
die();
}
$redis = new Redis();
if (!$redis->connect($settings['redis']['host'], $settings['redis']['port'])) { $log->error("Can't connect to redis"); die; }

if (!empty($settings['redis']['prefix'])) $redis->setOption(Redis::OPT_PREFIX, $settings['redis']['prefix']);
if (!empty($settings['redis']['auth']) && !$redis->auth($settings['redis']['auth'])) {
$log->error("Can't connect to redis, autentication failed"); die;
}

$redis = new Redis();
$redis->connect("127.0.0.1");

include "Modules/feed/feed_model.php";
$feed = new Feed($mysqli,$redis,$settings["feed"]);

// ----------------------------------------------------
// Grid Carbon
// ----------------------------------------------------

$timestamp = floor(time()/1800)*1800;
$date = new DateTime();
$date->setTimezone(new DateTimeZone("Europe/London"));
Expand All @@ -12,6 +48,56 @@
$redis->set("demandshaper:carbonintensity",$result);
print "$start carbonintensity ".strlen($result)."\n";

$result = file_get_contents("https://api.octopus.energy/v1/products/AGILE-18-02-21/electricity-tariffs/E-1R-AGILE-18-02-21-D/standard-unit-rates/");
$redis->set("demandshaper:octopus",$result);
print "$start octopus ".strlen($result)."\n";
// ----------------------------------------------------
// Octopus Agile
// ----------------------------------------------------

// Option:
// Enter feed id's here that price signals are to be written to
// or leave as zero to just cache latest price signals in redis
$regions = array(
"A"=>0,
"B"=>0,
"C"=>0,
"D"=>0,
"E"=>0,
"F"=>0,
"G"=>0,
"H"=>0,
"J"=>0,
"K"=>0,
"L"=>0,
"M"=>0,
"N"=>0,
"P"=>0
);

// Uncomment to load in history
// for ($i=465; $i>0; $i--) {
foreach ($regions as $gsp_id=>$feedid) {
if ($result = json_decode(file_get_contents("https://api.octopus.energy/v1/products/AGILE-18-02-21/electricity-tariffs/E-1R-AGILE-18-02-21-$gsp_id/standard-unit-rates/"))) {
if ($result!=null && isset($result->results)) {
$redis->set("demandshaper:octopus:$gsp_id",json_encode($result));

if ($feedid>0) {
// sort octopus forecast into time => price associative array
$octopus = array();
foreach ($result->results as $row) {
$date = new DateTime($row->valid_from);
$date->setTimezone(new DateTimeZone("Europe/London"));
$octopus[$date->getTimestamp()] = $row->value_exc_vat;
}

ksort($octopus);

$data = array();
foreach ($octopus as $time=>$value) {
// print $feedid." ".$time." ".$value."\n";
$feed->insert_data($feedid,$time,$time,$value);
}
}
}
print "$gsp_id ok\n";
}
}
//}
68 changes: 68 additions & 0 deletions tests/smartplug_sim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import time
import paho.mqtt.client as mqtt

device = "smartplug1272"
mqtt_user = "emonpi"
mqtt_passwd = "emonpimqtt2016"
mqtt_host = "localhost"
mqtt_port = 1883

basetopic = "emon"
# basetopic = "user/"+str(userid) # multiuser

ctrlmode = "off"
timer = "0000 0000 0000 0000"

def on_connect(client, userdata, flags, rc):
# Initialisation string
mqttc.subscribe(basetopic+"/"+device+"/in/#")
pass

def on_message(client, userdata, msg):
global ctrlmode, timer

print msg.topic+": "+msg.payload

# Set control mode: On, Off, Timer
if msg.topic==basetopic+"/"+device+"/in/ctrlmode":
ctrlmode = msg.payload

# Set timer: start1 stop1 start2 stop2
if msg.topic==basetopic+"/"+device+"/in/timer":
ctrlmode = "Timer"
timer = msg.payload

# Fetch and return smartplug state
if msg.topic==basetopic+"/"+device+"/in/state":
value = '{"ip":"192.168.1.71","time":0,"ctrlmode":"'+ctrlmode+'","timer":"'+timer+'","vout":0}'
print basetopic+"/"+device+"/out/state"+" "+value+"\n"
mqttc.publish(basetopic+"/"+device+"/out/state",value,2)

mqttc = mqtt.Client("smartplug-remote")
mqttc.on_connect = on_connect
mqttc.on_message = on_message

# Connect
try:
mqttc.username_pw_set(mqtt_user, mqtt_passwd)
mqttc.connect(mqtt_host, mqtt_port, 60)
mqttc.loop_start()
except Exception:
print "Could not connect to MQTT"
else:
print "Connected to MQTT"

time.sleep(1)

# Loop
while 1:
# Sent a device parameter
topic = basetopic+"/"+device+"/temperature"
value = 18.5
mqttc.publish(topic,value,2)
time.sleep(10)

# Close
mqttc.loop_stop()
mqttc.disconnect()

0 comments on commit 1eaa3ef

Please sign in to comment.