'Logger settings', 'description' => 'Configure settings for logging metering values.', 'page callback' => 'drupal_get_form', 'page arguments' => array('_logger_admin_settings'), 'access arguments' => array('administer site configuration'), ); $items['logger'] = array( 'title' => 'your dashboard', // isn't printed as title on the page, therefore resort to drupal_set_title (t('your ecological dashboard')) in ecology_dashboard; 'description' => 'Configure settings for logging metering values.', 'page callback' => '_logger_dashboard', //takes the callback from the MENU_DEFAULT_LOCAL_TASK -> lightest level-two menu 'page arguments' => array('electricity', 'main', 'hour'), 'access callback' => TRUE, 'type' => MENU_CALLBACK, ); $items['logger/add'] = array( 'title' => 'add this user to the chart', 'page callback' => '_logger_add', 'access arguments' => array('logger'), 'type' => MENU_CALLBACK, ); $items['logger/remove'] = array( 'title' => 'remove this user from the chart', 'page callback' => '_logger_remove', 'access arguments' => array('logger'), 'type' => MENU_CALLBACK, ); $items['logger/unit'] = array( 'title' => 'change the unit', 'page callback' => '_logger_unit', 'access arguments' => array('logger'), 'type' => MENU_CALLBACK, ); $items['logger/electricity'] = array( 'title' => 'electricity', // 'page callback' => '_logger_dashboard', // 'page arguments' => array('electricity', 'main', 'hour'), 'access callback' => TRUE, 'type' => MENU_DEFAULT_LOCAL_TASK, ); /** $items['logger/water'] = array( 'title' => 'water', 'page callback' => '_logger_dashboard', 'page arguments' => array('water', 'main', 'hour'), 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, ); $items['logger/gas'] = array( 'title' => 'gas', 'page callback' => '_logger_dashboard', 'page arguments' => array('gas', 'main', 'hour'), 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, ); **/ $items['logger/electricity/hour'] = array( 'title' => 'hour', 'page callback' => '_logger_dashboard', 'page arguments' => array('electricity', 'main', 'hour'), 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 0, ); $items['logger/electricity/day'] = array( 'title' => 'day', 'page callback' => '_logger_dashboard', 'page arguments' => array('electricity', 'main', 'day'), 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 1, ); $items['logger/electricity/month'] = array( 'title' => 'month', 'page callback' => '_logger_dashboard', 'page arguments' => array('electricity', 'main', 'month'), 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 2, ); $items['logger/electricity/year'] = array( 'title' => 'year', 'page callback' => '_logger_dashboard', 'page arguments' => array('electricity', 'main', 'year'), 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 3, ); $items['logger/electricity/night'] = array( 'title' => 'night', 'page callback' => '_logger_dashboard', 'page arguments' => array('electricity', 'main', 'night'), 'access callback' => TRUE, 'type' => MENU_LOCAL_TASK, 'weight' => 4, ); return $items; } /** * Callback functions registered in the logger_menu section */ function _logger_dashboard($type, $function, $interval) { // watchdog('dashboard', 'arguments: %type, %function, %interval', array('%type' => $type, '%function' => $function, '%interval' => $interval), WATCHDOG_DEBUG); if (user_access('logger')) { drupal_set_title(t('your dashboard')); global $user; } else { //show users who don't have 'logger' permissions icrarus'es chart drupal_set_title(t("a Fluksonian's dashboard")); $user = new stdClass(); $user->uid = 1; $user->name = 'icarus75'; $user->timezone = '3600'; } $root_path = drupal_get_path('module', 'logger'); $graph_path = $root_path .'/graphs/'. $interval .'/'; $pngid = md5(uniqid()); //generate random numbers for the png chart so that the browser doesn't use the cached one, use cron to clean up the dir hourly switch ($interval) { case 'hour': $data_path = $root_path .'/data/base/'; $start = 'end-1h'; break; case 'day': $data_path = $root_path .'/data/base/'; $start = 'end-1d'; break; case 'month': $data_path = $root_path .'/data/base/'; $start = 'end-60d'; break; case 'year': $data_path = $root_path .'/data/base/'; $start = 'end-1y'; break; case 'night': $data_path = $root_path .'/data/night/'; $start = 'end-60d'; break; } $meter = db_fetch_object(db_query("SELECT meter, unit FROM {logger_meters} WHERE uid = %d AND type = '%s' AND function = '%s'", $user->uid, $type, $function)); switch ($type) { case 'electricity': switch ($meter->unit) { case 'watt': $meter->factor = 3600; // 1Wh/s = 3600 W break; case 'kwh': $meter->unit = 'kWh/year'; $meter->factor = 31536; break; case 'eur': $meter->unit = 'euro/year'; $meter->factor = 5361.12; break; } } $color = array(RED, BLUE, GREEN, YELLOW, PURPLE); $string->def = ' DEF:data0='. $data_path . $meter->meter .'.rrd:meter:AVERAGE CDEF:meter0=data0,'. $meter->factor .',* VDEF:min0=meter0,MINIMUM VDEF:max0=meter0,MAXIMUM VDEF:avg0=meter0,AVERAGE VDEF:last0=meter0,LAST'; $string->line = ' COMMENT:"\s" LINE1:meter0#'. $color[0] .':'.'"'. substr($user->name.' ', 0, 15) .'"'.' GPRINT:min0:"min\:%5.0lf" GPRINT:max0:"\tmax\:%5.0lf" GPRINT:avg0:"\tavg\:%5.0lf" GPRINT:last0:"\tlast\:%5.0lf\l"'; if (user_access('logger') || user_access('staff')) { //allow Veerle to watch the graphs $result = db_query("SELECT u.name, lm.meter FROM (({users} u INNER JOIN {user_relationships} ur ON u.uid = ur.requestee_id) INNER JOIN {user_relationship_types} urt ON ur.rtid = urt.rtid) INNER JOIN {logger_meters} lm ON u.uid = lm.uid WHERE ur.requester_id = %d AND urt.name = '%s' AND type = '%s' AND function = '%s' ORDER BY ur.rid", $user->uid, 'subscription', $type, $function); $i = 0; while ($subscription = db_fetch_object($result)) { $i += 1; // print_r($subscription); $string->def .= ' DEF:data'. $i .'='. $data_path . $subscription->meter .'.rrd:meter:AVERAGE CDEF:meter'. $i .'=data'. $i .','. $meter->factor .',* VDEF:min'. $i .'=meter'. $i .',MINIMUM VDEF:max'. $i .'=meter'. $i .',MAXIMUM VDEF:avg'. $i .'=meter'. $i .',AVERAGE VDEF:last'. $i .'=meter'. $i .',LAST'; $string->line .= ' LINE1:meter'. $i .'#'. $color[$i] .':'.'"'. substr($subscription->name.' ', 0, 15) .'"'.' GPRINT:min'. $i .':"min\:%5.0lf" GPRINT:max'. $i .':"\tmax\:%5.0lf" GPRINT:avg'. $i .':"\tavg\:%5.0lf" GPRINT:last'. $i .':"\tlast\:%5.0lf\l"'; } } //construct the TZ=GMT-02:00 format from the $user->timezone object updated by the autotimezone module if ($user->timezone >= 0) $TZ = 'TZ="GMT-'; else $TZ = 'TZ="GMT+'; $TZ .= gmdate('h:i', abs($user->timezone)) .'" '; //insert the TZ prior to launching rrdtool to obtain a proper time conversion $command = $TZ . $root_path .'/rrdtool graph '. $graph_path . $pngid .'.png -s '. $start .' --vertical-label '. $meter->unit .' --lower-limit 0 -w 500 -h 350 -E -X 0 --font LEGEND:8:'; $command .= $string->def; $command .= $string->line; exec($command, $output, $return_var); // watchdog('dashboard', 'arguments: %command ++ %output ++ %return_var', array('%command' => $command, '%output' => serialize($output), '%return_var' => $return_var), WATCHDOG_DEBUG); return theme('chart', $graph_path . $pngid .'.png'); } function _logger_add($uid) { global $user; $rtid = db_result(db_query("SELECT rtid FROM {user_relationship_types} WHERE name = '%s'", 'subscription')); $result = db_fetch_array(db_query("SELECT COUNT(rid), MAX(rid) FROM {user_relationships} WHERE requester_id = %d AND rtid = %d GROUP BY rtid", $user->uid, $rtid)); // max subscriptions = 4 if ($result['COUNT(rid)'] < 4) { user_relationships_request_relationship($user->uid, $uid, $rtid, TRUE); } else { //check whether the requested relationship doesn't already exist if (!db_result(db_query("SELECT rid FROM {user_relationships} WHERE requester_id = %d AND requestee_id = %d AND rtid = %d", $user->uid, $uid, $rtid))) { // if not, delete the most recently added relationship and replace it with the newly selected one db_query("DELETE FROM {user_relationships} WHERE rid = %d", $result['MAX(rid)']); user_relationships_request_relationship($user->uid, $uid, $rtid, TRUE); } } $destination = drupal_get_destination(); drupal_goto($destination); } function _logger_remove($rid) { global $user; // check whether the to-be-deleted relationship was created by the same user if ($user->uid == db_result(db_query("SELECT requester_id FROM {user_relationships} WHERE rid = %d", $rid))) { db_query("DELETE FROM {user_relationships} WHERE rid = %d", $rid); } else { watchdog('relationships', 'attempt to delete rid %rid by non-authorized user %uid', array('%rid' => $rid, '%uid' => $user->uid), WATCHDOG_ERROR); } $destination = drupal_get_destination(); drupal_goto($destination); } function _logger_unit($unit) { // TODO : include security checks global $user; // hardcoded type and function db_query("UPDATE {logger_meters} SET unit = '%s' WHERE uid = %d AND type = '%s' AND function = '%s'", $unit, $user->uid, 'electricity', 'main'); $destination = drupal_get_destination(); drupal_goto($destination); } /** * Implementation of hook_theme() for logger */ function logger_theme() { return array( 'chart' => array( 'arguments' => array('chart' => NULL), ), 'logger_item_list' => array( 'arguments' => array('items' => NULL, 'title' => NULL), ), ); } /** * Theming the chart */ function theme_chart($chart) { $output .= '

Flukso

'; return $output; } /** * Implementation of hook_block() for logger * Adds two blocks to the logger pages for (de-)selecting users and * another one for selecting the desired unit */ function logger_block($op = 'list', $delta = 0, $edit = array()) { global $user; switch ($op) { case 'list': $blocks['subscriptions']['info'] = t('Subscriptions'); $blocks['subscriptions']['status'] = TRUE; $blocks['subscriptions']['region'] = 'right'; $blocks['subscriptions']['weight'] = 0; $blocks['subscriptions']['pages'] = 'logger
logger/*'; $blocks['fluksonians']['info'] = t('Fluksonians'); $blocks['fluksonians']['status'] = TRUE; $blocks['fluksonians']['region'] = 'right'; $blocks['fluksonians']['weight'] = 1; $blocks['fluksonians']['pages'] = 'logger
logger/*'; $blocks['unit']['info'] = t('Unit'); $blocks['unit']['status'] = TRUE; $blocks['unit']['region'] = 'right'; $blocks['unit']['weight'] = 2; $blocks['unit']['pages'] = 'logger
logger/*'; $blocks['publish']['info'] = t('Publish'); $blocks['publish']['status'] = TRUE; $blocks['publish']['region'] = 'content'; $blocks['publish']['weight'] = 3; $blocks['publish']['pages'] = 'logger
logger/*'; return $blocks; case 'view': //pass along our current destination in the query string so that logger_add and logger_remove can return after processing their task $destination = drupal_get_destination(); if ($delta == 'subscriptions' && user_access('logger')) { $result = db_query("SELECT u.uid, u.name, ur.rid FROM ({users} u INNER JOIN {user_relationships} ur ON u.uid = ur.requestee_id) INNER JOIN {user_relationship_types} urt ON ur.rtid = urt.rtid WHERE ur.requester_id = %d AND urt.name = '%s' ORDER BY ur.rid", $user->uid, 'subscription'); $items = array(); while ($subscription = db_fetch_object($result)) { $items[] = l('[x]', 'logger/remove/'. $subscription->rid, array('attributes' => array('title' => "unsubscribe from ". $subscription->name ."'s stream"), 'query' => $destination, 'alias' => TRUE)) .' '. l($subscription->name, 'user/'. $subscription->uid, array('alias' => FALSE)); } $block['subject'] = t('Subscriptions'); $block['content'] = theme('logger_item_list', $items); } elseif ($delta == 'fluksonians' && user_access('logger')) { // list all users having the fluksionian role for now // to be replaced by a real buddylist later on $result = db_query("SELECT u.uid, u.name FROM ({users} u INNER JOIN {users_roles} ur ON u.uid = ur.uid) INNER JOIN {role} r ON ur.rid = r.rid WHERE r.name = '%s' AND NOT u.uid = %d ORDER BY u.name", 'fluksonian', $user->uid); $items = array(); while ($fluksonian = db_fetch_object($result)) { $items[] = l('[+]', 'logger/add/'. $fluksonian->uid, array('attributes' => array('title' => "subscribe to ". $fluksonian->name ."'s stream"), 'query' => $destination, 'alias' => TRUE)) .' '. l($fluksonian->name, 'user/'. $fluksonian->uid, array('alias' => FALSE)); } $block['subject'] = t('Fluksonians'); $block['content'] = theme('logger_item_list', $items); } elseif ($delta == 'unit' && user_access('logger')) { //hardcoded the type and function parameters for now $unit = db_result(db_query("SELECT unit FROM {logger_meters} WHERE uid = %d AND type = '%s' AND function = '%s'", $user->uid, 'electricity', 'main')); $items = array(); switch ($unit) { case 'watt': $items[] = 'watt'; $items[] = l('kWh/year', 'logger/unit/kwh', array('attributes' => array('title' => "switch to kWh/year"), 'query' => $destination, 'alias' => TRUE)); $items[] = l('euro/year', 'logger/unit/eur', array('attributes' => array('title' => "switch to euro/year"), 'query' => $destination, 'alias' => TRUE)); break; case 'kwh': $items[] = l('watt', 'logger/unit/watt', array('attributes' => array('title' => "switch to watt"), 'query' => $destination, 'alias' => TRUE)); $items[] = 'kWh/year'; $items[] = l('euro/year', 'logger/unit/eur', array('attributes' => array('title' => "switch to euro/year"), 'query' => $destination, 'alias' => TRUE)); break; case 'eur': $items[] = l('watt', 'logger/unit/watt', array('attributes' => array('title' => "switch to watt"), 'query' => $destination, 'alias' => TRUE)); $items[] = l('kWh/year', 'logger/unit/kwh', array('attributes' => array('title' => "switch to kWh/year"), 'query' => $destination, 'alias' => TRUE)); $items[] = 'euro/year'; break; } $block['subject'] = t('Unit'); $block['content'] = theme('logger_item_list', $items); } elseif ($delta == 'publish' && user_access('logger')) { // $block['subject'] = t('Publish'); $block['content'] = drupal_get_form('_logger_publish_form'); } return $block; } } /** * Implementing a simple non-bulleted list for the logger_block */ function theme_logger_item_list($items, $title = NULL) { $output = ''; foreach ($items as $item) { $output .= $item .'
'; } return $output; } /** * Generates the publish block form. */ function _logger_publish_form() { $form['publish'] = array( '#type' => 'fieldset', '#title' => t('Publish'), '#description' => t('Publish the chart.'), '#collapsible' => TRUE, '#collapsed' => TRUE ); $form['publish']['title'] = array( '#type' => 'textfield', '#title' => t('Title'), '#description' => t('Please enter the title of your post.') ); $form['publish']['submit'] = array( '#type' => 'submit', '#value' => t('Publish') ); return $form; } /** * Process publish form submissions. */ function _logger_publish_form_submit($form, &$form_state) { $form_state['redirect'] = 'node/add'; //placeholder; check whether we can automatically fill in the new content type } /** * Define the administration settings form for the logger module */ function _logger_admin_settings() { //TODO } /** * Implementation of hook_cron(). * Cron will call this hook periodically [e.g. 1 hour interval] to perform housekeeping on the png's. */ function logger_cron() { exec('rm sites/all/modules/logger/graphs/hour/*'); exec('rm sites/all/modules/logger/graphs/day/*'); exec('rm sites/all/modules/logger/graphs/month/*'); exec('rm sites/all/modules/logger/graphs/year/*'); exec('rm sites/all/modules/logger/graphs/night/*'); }