mirror of
				https://github.com/beestat/app.git
				synced 2025-10-31 01:57:01 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			177 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			PHP
		
	
	
		
			Executable File
		
	
	
	
	
| <?php
 | |
| 
 | |
| /**
 | |
|  * All of the raw thermostat data sits here. Many millions of rows.
 | |
|  *
 | |
|  * @author Jon Ziebell
 | |
|  */
 | |
| class runtime_thermostat extends cora\crud {
 | |
| 
 | |
|   public static $exposed = [
 | |
|     'private' => [
 | |
|       'read'
 | |
|     ],
 | |
|     'public' => []
 | |
|   ];
 | |
| 
 | |
|   public static $cache = [
 | |
|     'read' => 900 // 15 Minutes
 | |
|   ];
 | |
| 
 | |
|   /**
 | |
|    * The user_id column is not present on this table to reduce data overhead.
 | |
|    * No public reads are performed on this table so as long as thermostat_id
 | |
|    * is always used on reads in this class then this is fine.
 | |
|    */
 | |
|   public static $user_locked = false;
 | |
| 
 | |
|   /**
 | |
|    * Read data from the runtime_thermostat table. Basically just a crud read
 | |
|    * but has custom security for thermostat_id since user_id is not on the
 | |
|    * table.
 | |
|    *
 | |
|    * @param array $attributes Timestamps can be specified in any format. If no
 | |
|    * time zone information is sent, UTC is assumed.
 | |
|    * @param array $columns
 | |
|    *
 | |
|    * @return array
 | |
|    */
 | |
|   public function read($attributes = [], $columns = []) {
 | |
|     $this->user_lock($attributes['thermostat_id']);
 | |
| 
 | |
|     // Check for exceptions.
 | |
|     if (isset($attributes['thermostat_id']) === false) {
 | |
|       throw new \Exception('Missing required attribute: thermostat_id.', 10201);
 | |
|     }
 | |
| 
 | |
|     if (isset($attributes['timestamp']) === false) {
 | |
|       throw new \Exception('Missing required attribute: timestamp.', 10202);
 | |
|     }
 | |
| 
 | |
|     if (
 | |
|       is_array($attributes['timestamp']) === true &&
 | |
|       in_array($attributes['timestamp']['operator'], ['>', '>=', '<', '<=']) === true &&
 | |
|       is_array($attributes['timestamp']['value']) === true
 | |
|     ) {
 | |
|       if(count($attributes['timestamp']['value']) === 1) {
 | |
|         $attributes['timestamp']['value'] = $attributes['timestamp']['value'][0];
 | |
|       } else {
 | |
|         throw new \Exception('Must only specify one timestamp value unless using the "between" operator.', 10204);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     $thermostat = $this->api('thermostat', 'get', $attributes['thermostat_id']);
 | |
|     $max_range = 2678000; // 31 days
 | |
|     if (
 | |
|       (
 | |
|         is_array($attributes['timestamp']) === true &&
 | |
|         $attributes['timestamp']['operator'] === 'between' &&
 | |
|         abs(strtotime($attributes['timestamp']['value'][0]) - strtotime($attributes['timestamp']['value'][1]))  > $max_range
 | |
|       ) ||
 | |
|       (
 | |
|         is_array($attributes['timestamp']) === true &&
 | |
|         in_array($attributes['timestamp']['operator'], ['>', '>=']) === true &&
 | |
|         time() - strtotime($attributes['timestamp']['value']) > $max_range
 | |
|       ) ||
 | |
|       (
 | |
|         is_array($attributes['timestamp']) === true &&
 | |
|         in_array($attributes['timestamp']['operator'], ['<', '<=']) === true &&
 | |
|         strtotime($attributes['timestamp']['value']) - min(strtotime($thermostat['first_connected']), strtotime($thermostat['sync_begin'])) > $max_range
 | |
|       )
 | |
|     ) {
 | |
|       throw new \Exception('Max range is 31 days.', 10205);
 | |
|     }
 | |
| 
 | |
|     // Accept timestamps in roughly any format; always convert back to something nice and in UTC
 | |
|     if (is_array($attributes['timestamp']['value']) === true) {
 | |
|       $attributes['timestamp']['value'][0] = date('c', strtotime($attributes['timestamp']['value'][0]));
 | |
|       $attributes['timestamp']['value'][1] = date('c', strtotime($attributes['timestamp']['value'][1]));
 | |
|     } else {
 | |
|       $attributes['timestamp']['value'] = date('c', strtotime($attributes['timestamp']['value']));
 | |
|     }
 | |
| 
 | |
|     // Read the data.
 | |
|     $runtime_thermostats = $this->database->read(
 | |
|       'runtime_thermostat',
 | |
|       [
 | |
|         'timestamp' => $attributes['timestamp'],
 | |
|         'thermostat_id' => $attributes['thermostat_id']
 | |
|       ],
 | |
|       [],
 | |
|       'timestamp' // order by
 | |
|     );
 | |
| 
 | |
|     // Get the appropriate runtime_thermostat_texts.
 | |
|     $runtime_thermostat_text_ids = array_unique(array_merge(
 | |
|       array_column($runtime_thermostats, 'event_runtime_thermostat_text_id'),
 | |
|       array_column($runtime_thermostats, 'climate_runtime_thermostat_text_id')
 | |
|     ));
 | |
|     $runtime_thermostat_texts = $this->api(
 | |
|       'runtime_thermostat_text',
 | |
|       'read_id',
 | |
|       [
 | |
|         'attributes' => [
 | |
|           'runtime_thermostat_text_id' => $runtime_thermostat_text_ids
 | |
|         ]
 | |
|       ]
 | |
|     );
 | |
| 
 | |
|     // Clean up the data just a bit.
 | |
|     foreach ($runtime_thermostats as &$runtime_thermostat) {
 | |
|       $runtime_thermostat['timestamp'] = date(
 | |
|         'c',
 | |
|         strtotime($runtime_thermostat['timestamp'])
 | |
|       );
 | |
| 
 | |
|       foreach([
 | |
|         'indoor_temperature',
 | |
|         'outdoor_temperature',
 | |
|         'setpoint_cool',
 | |
|         'setpoint_heat'
 | |
|       ] as $key) {
 | |
|         if ($runtime_thermostat[$key] !== null) {
 | |
|           $runtime_thermostat[$key] /= 10;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if ($runtime_thermostat['event_runtime_thermostat_text_id'] !== null) {
 | |
|         $runtime_thermostat['event'] = $runtime_thermostat_texts[
 | |
|           $runtime_thermostat['event_runtime_thermostat_text_id']
 | |
|         ]['value'];
 | |
|       } else {
 | |
|         $runtime_thermostat['event'] = null;
 | |
|       }
 | |
|       unset($runtime_thermostat['event_runtime_thermostat_text_id']);
 | |
| 
 | |
|       if ($runtime_thermostat['climate_runtime_thermostat_text_id'] !== null) {
 | |
|         $runtime_thermostat['climate'] = $runtime_thermostat_texts[
 | |
|           $runtime_thermostat['climate_runtime_thermostat_text_id']
 | |
|         ]['value'];
 | |
|       } else {
 | |
|         $runtime_thermostat['climate'] = null;
 | |
|       }
 | |
|       unset($runtime_thermostat['climate_runtime_thermostat_text_id']);
 | |
|     }
 | |
| 
 | |
|     return $runtime_thermostats;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Since this table does not have a user_id column, security must be handled
 | |
|    * manually. Call this with a thermostat_id to verify that the current user
 | |
|    * has access to the requested thermostat.
 | |
|    *
 | |
|    * @param int $thermostat_id
 | |
|    *
 | |
|    * @throws \Exception If the current user doesn't have access to the
 | |
|    * requested thermostat.
 | |
|    */
 | |
|   private function user_lock($thermostat_id) {
 | |
|     $thermostats = $this->api('thermostat', 'read_id');
 | |
|     if (isset($thermostats[$thermostat_id]) === false) {
 | |
|       throw new \Exception('Invalid thermostat_id.', 10203);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| }
 |