ctucx.git: ansible-configs

My personal ansible roles and playbooks [deprecated in favor of nixos]

commit ffdcab3e634d28ca63e31ee5dfeafa4aaaab4db1
parent 555cc68c5250996820e4beea5405f1c806157fd7
Author: Leah (ctucx) <leah@ctu.cx>
Date: Wed, 3 Feb 2021 18:21:15 +0100

add smartied-config and powermeter-archiver script
2 files changed, 1067 insertions(+), 0 deletions(-)
A
config-files/smartied/config.json
|
116
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
scripts/powermeter-archiver.php
|
951
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/config-files/smartied/config.json b/config-files/smartied/config.json
@@ -0,0 +1,116 @@
+{
+ 	"devices": {
+		"modbus-10": {
+			"type": "RelayBoard",
+			"firstRegister": 0,
+			"count": 8,
+			"address": 10
+		},
+		"modbus-50": {
+			"type": "PowerMeter",
+			"model": "SDM120",
+			"address": 50
+		},
+		"modbus-60": {
+			"type": "PowerMeter",
+			"model": "SDM120",
+			"address": 60
+		},
+		"lacrosse-raum": {
+			"type": "LacrosseTempSensor",
+			"id": "5",
+			"address": 5
+		},
+		"lacrosse-draussen": {
+			"type": "LacrosseTempSensor",
+			"id": "31",
+			"address": 31
+		},
+		"lacrosse-bad": {
+			"type": "LacrosseTempSensor",
+			"id": "3f",
+			"address": 42
+		}
+	},
+	"clientConfigs": {
+		"smarthome-pwa": {
+			"views": [
+				{
+					"url": "lights",
+					"name": "Lights",
+					"icon": "lightbulb",
+					"type": "switches",
+					"switches": [
+						{ "name": "Decke", "device": "modbus-10", "relay": 0 },
+						{ "name": "Bett", "device": "modbus-10", "relay": 1 },
+						{ "name": "Küche", "device": "modbus-10", "relay": 2 },
+						{ "name": "Regal", "device": "modbus-10", "relay": 7 },
+						{ "name": "Bad", "device": "modbus-10", "relay": 3 }
+					]
+				},
+				{
+					"url": "switches",
+					"name": "Switches",
+					"icon": "power_settings_new",
+					"type": "switches",
+					"switches": [
+                                                { "name": "Bett-Monitor", "device": "modbus-10", "relay": 5 },
+						{ "name": "Verstärker", "device": "modbus-10", "relay": 6 }
+					]
+				},
+				{
+					"url": "powermeter",
+					"name": "Power Meter",
+					"icon": "power",
+					"type": "powermeter",
+					"meters": [
+						{ "name": "Sonstiges", "device": "modbus-50" },
+						{ "name": "Küche", "device": "modbus-60" }
+					]
+				},
+				{
+					"url": "temperature",
+					"name": "Temperature",
+					"icon": "brightness_7",
+					"type": "temperature",
+					"sensors": [
+						{ "name": "Raum", "device": "lacrosse-raum" },
+						{ "name": "Bad", "device": "lacrosse-bad" },
+						{ "name": "Draussen", "device": "lacrosse-draussen" }
+					]
+				},
+				{
+					"url": "departures",
+					"name": "Departures",
+					"icon": "departure_board",
+					"type": "departures",
+					"source": "https://f2k1.de/haltestellen.php"
+				},
+				{
+					"url": "fritzbox",
+					"name": "Fritz!Box",
+					"icon": "router",
+					"type": "redirect",
+					"destination": "http://192.168.178.1/"
+				},
+				{
+					"url": "settings",
+					"name": "Settings",
+					"icon": "settings",
+					"type": "settings",
+					"sourceLink": "https://cgit.ctu.cx/smarthome-pwa"
+				}
+			]
+		}
+	},
+	"httpPort": 5000,
+	"tcpPort": 5001,
+	"wsPort": 5002,
+	"prometheusPort": 5003,
+	"modbusAddr": "10.0.0.1",
+	"modbusPort": 502,
+	"lacrosseAddr": "10.0.0.1",
+	"lacrossePort": 2342,
+	"powermeterUpdateIntervalSec": 20,
+	"accessToken": "penis123"
+}
diff --git a/scripts/powermeter-archiver.php b/scripts/powermeter-archiver.php
@@ -0,0 +1,951 @@
+#!/usr/bin/php
+<?php
+ini_set('precision', -1);
+ini_set('serialize_precision', -1);
+date_default_timezone_set('Europe/Berlin');
+
+
+$path = '/var/lib/powermeter-archive/';
+
+if (!file_exists($path)) {
+	mkdir($path);
+	mkdir($path.'minute/');
+	mkdir($path.'day/');
+	mkdir($path.'week/');
+	mkdir($path.'month/');
+}
+
+$curl = new CurlWrapper();
+$curl->addHeader("Authorization", "Bearer penis123");
+$response = $curl->get('http://127.0.0.1:5000/');
+$smartie_data = json_decode($response, true);
+
+$metadata = json_decode(file_get_contents($path.'metadata.json'), true);
+
+
+foreach ($smartie_data as $id => $data) {
+	if ($data['type'] !== 'PowerMeter') continue;
+
+	if (!in_array($id, $metadata['devices'])) {
+		$metadata['devices'][] = $id;
+	}
+
+	ArchiveData('minute', $path, $id, [$data]);
+	ArchiveData('day', $path, $id, [$data]);
+	ArchiveData('week', $path, $id, [$data]);
+	ArchiveData('month', $path, $id, [$data]);
+
+	$year  = date('Y', $data['lastUpdated']);
+	$month = date('m', $data['lastUpdated']);
+
+	if (!isset($metadata['availableData'][$year])) {
+		$metadata['availableData'][$year] = [];
+	}
+
+	if (!in_array($month, $metadata['availableData'][$year])) {
+		$metadata['availableData'][$year][] = $month;
+	}
+}
+
+$metadata['lastUpdated'] = time();
+
+file_put_contents($path.'metadata.json', json_encode($metadata));
+
+///
+
+
+function ArchiveData ($mode, $path, $id, $new_data) {
+	$modes = [
+			'minute' => [
+					'id_format' => 'YmdHi',
+					'fn_format' => 'Y_m_d',					
+				],	
+			'day'   => [
+					'id_format' => 'Ymd',
+					'fn_format' => 'Y_m',
+				],
+			'week'  => [
+					'id_format' => 'YW',
+					'fn_format' => 'Y',
+				],
+			'month' => [
+					'id_format' => 'Ym',
+					'fn_format' => 'Y',
+				],
+		];
+
+	if (!isset($modes[$mode])) return;
+
+	$cache = [];
+
+	foreach ($new_data as $datapoint) {
+		$entry_id = date($modes[$mode]['fn_format'], $datapoint['lastUpdated']);
+		$cache[$entry_id][] = $datapoint;
+	}
+
+	foreach ($cache as $file_name => $data) {
+		$db_file = $path.$mode.'/'.$id.'_'.$file_name.'.json';
+		$db      = readFromFile($db_file);
+
+		if ($mode !== 'minute') {
+			foreach ($data as $entry) {				
+				$last_timestamp = strtotime('-1 '.$mode, $entry['lastUpdated']);
+				$last_id        = date($modes[$mode]['id_format'], $last_timestamp);
+
+				$last = [
+						'imported'      => $entry['import'],
+						'totalImported' => $entry['import'],
+						'lastUpdated'   => $entry['lastUpdated'],
+					];
+
+				if (date($modes[$mode]['fn_format'], $last_timestamp) !== date($modes[$mode]['fn_format'], $entry['lastUpdated'])) {
+					$last_file = $path.$mode.'/'.$id.'_'.date($modes[$mode]['fn_format'], $last_timestamp).'.json';
+					$last_db   = readFromFile($last_file);
+
+					if (!isset($last_db[$last_id])) {
+						$last_db[$last_id] = $last;
+						writeToFile($last_file, $last_db);
+					} else {
+						$last = $last_db[$last_id];
+					}
+				} else {
+					if (!isset($db[$last_id])) {
+						$db[$last_id] = $last;
+					} else {
+						$last = $db[$last_id];
+					}	
+				}
+
+				$entry_id = date($modes[$mode]['id_format'], $entry['lastUpdated']);
+				$db[$entry_id] = [
+						'imported'      => $entry['import'] - $last['totalImported'],
+						'totalImported' => $entry['import'],
+						'lastUpdated'   => $entry['lastUpdated'],
+					];
+			}
+
+		} else {
+			foreach ($data as $entry) {
+				$entry_id = date($modes[$mode]['id_format'], $entry['lastUpdated']);
+				$db[$entry_id] = $entry;
+			}
+		}
+
+		writeToFile($db_file, $db);
+	}
+}
+
+function readFromFile ($file) {
+	if (!file_exists($file)) {
+		return [];
+	} else {
+		return json_decode(file_get_contents($file), true);
+	}
+}
+
+function writeToFile ($file, $data) {
+	file_put_contents($file, json_encode($data));
+}
+
+
+/**
+ * CurlWrapper - Flexible wrapper class for PHP cURL extension
+ *
+ * @author Leonid Svyatov <leonid@svyatov.ru>
+ * @copyright 2010-2011, 2014 Leonid Svyatov
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 1.3.0
+ * @link http://github.com/svyatov/CurlWrapper
+ */
+class CurlWrapper
+{
+    /**
+     * @var resource cURL handle
+     */
+    protected $ch = null;
+    /**
+     * @var string Filename of a writable file for cookies storage
+     */
+    protected $cookieFile = '';
+    /**
+     * @var array Cookies to send
+     */
+    protected $cookies = array();
+    /**
+     * @var array Headers to send
+     */
+    protected $headers = array();
+    /**
+     * @var array cURL options
+     */
+    protected $options = array();
+    /**
+     * @var array Predefined user agents. The 'chrome' value is used by default
+     */
+    protected static $predefinedUserAgents = array(
+        // IE 11
+        'ie'       => 'Mozilla/5.0 (compatible; MSIE 11.0; Windows NT 6.1; WOW64; Trident/6.0)',
+        // Firefox 29
+        'firefox'  => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20120101 Firefox/29.0',
+        // Opera 20
+        'opera'    => 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.46 Safari/537.36 OPR/20.0.1387.24 (Edition Next)',
+        // Chrome 32
+        'chrome'   => 'Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36',
+        // Google Bot
+        'bot'      => 'Googlebot/2.1 (+http://www.google.com/bot.html)',
+    );
+    /**
+     * @var array GET/POST params to send
+     */
+    protected $requestParams = array();
+    /**
+     * @var string cURL response data
+     */
+    protected $response = '';
+    /**
+     * @var array cURL transfer info
+     */
+    protected $transferInfo = array();
+
+    /**
+     * Initiates the cURL handle
+     *
+     * @throws CurlWrapperCurlException
+     */
+    public function __construct()
+    {
+        if (!extension_loaded('curl')) {
+            throw new CurlWrapperException('cURL extension is not loaded.');
+        }
+
+        $this->ch = curl_init();
+
+        if (!$this->ch) {
+            throw new CurlWrapperCurlException($this->ch);
+        }
+
+        $this->setDefaults();
+    }
+
+    /**
+     * Closes and frees the cURL handle
+     */
+    public function __destruct()
+    {
+        if (is_resource($this->ch)) {
+            curl_close($this->ch);
+        }
+
+        $this->ch = null;
+    }
+
+    /**
+     * Adds a cookie for a cURL transfer
+     *
+     * Examples:
+     * $curl->addCookie('user', 'admin');
+     * $curl->addCookie(array('user'=>'admin', 'test'=>1));
+     *
+     * @param string|array $name Name of cookie or array of cookies (name=>value)
+     * @param string $value Value of cookie
+     */
+    public function addCookie($name, $value = null)
+    {
+        if (is_array($name)) {
+            $this->cookies = $name + $this->cookies;
+        } else {
+            $this->cookies[$name] = $value;
+        }
+    }
+
+    /**
+     * Adds a header for a cURL transfer
+     *
+     * Examples:
+     * $curl->addHeader('Accept-Charset', 'utf-8;q=0.7,*;q=0.7');
+     * $curl->addHeader('Pragma', '');
+     * $curl->addHeader(array('Accept-Charset'=>'utf-8;q=0.7,*;q=0.7', 'Pragma'=>''));
+     *
+     * @param string|array $header Header or array of headers (header=>value)
+     * @param string $value Value of header
+     */
+    public function addHeader($header, $value = null)
+    {
+        if (is_array($header)) {
+            $this->headers = $header + $this->headers;
+        } else {
+            $this->headers[$header] = $value;
+        }
+    }
+
+    /**
+     * Adds an option for a cURL transfer (@see http://php.net/manual/en/function.curl-setopt.php)
+     *
+     * @param integer|array $option CURLOPT_XXX predefined constant or associative array of constants (constant=>value)
+     * @param mixed $value Value of option
+     */
+    public function addOption($option, $value = null)
+    {
+        if (is_array($option)) {
+            $this->options = $option + $this->options;
+        } else {
+            $this->options[$option] = $value;
+        }
+    }
+
+    /**
+     * Adds a request (GET/POST) parameter for a cURL transfer
+     *
+     * Examples:
+     * $curl->addRequestParam('param', 'test');
+     * $curl->addRequestParam('param=test&otherparam=123');
+     * $curl->addRequestParam(array('param'=>'test', 'otherparam'=>123));
+     *
+     * @param string|array $name Name of parameter, query string or array of parameters (name=>value)
+     * @param string $value Value of parameter
+     */
+    public function addRequestParam($name, $value = null)
+    {
+        if (is_array($name)) {
+            $this->requestParams = $name + $this->requestParams;
+        } elseif (is_string($name) && $value === null) {
+            parse_str($name, $params);
+            if (!empty($params)) {
+                $this->requestParams = $params + $this->requestParams;
+            }
+        } else {
+            $this->requestParams[$name] = $value;
+        }
+    }
+
+    /**
+     * Clears the cookies file
+     */
+    public function clearCookieFile()
+    {
+        if (!is_writable($this->cookieFile)) {
+            throw new CurlWrapperException('Cookie file "'.($this->cookieFile).'" is not writable or does\'n exists!');
+        }
+
+        file_put_contents($this->cookieFile, '', LOCK_EX);
+    }
+
+    /**
+     * Clears the cookies
+     */
+    public function clearCookies()
+    {
+        $this->cookies = array();
+    }
+
+    /**
+     * Clears the headers
+     */
+    public function clearHeaders()
+    {
+        $this->headers = array();
+    }
+
+    /**
+     * Clears the options
+     */
+    public function clearOptions()
+    {
+        $this->options = array();
+    }
+
+    /**
+     * Clears the request parameters
+     */
+    public function clearRequestParams()
+    {
+        $this->requestParams = array();
+    }
+
+    /**
+     * Makes the 'DELETE' request to the $url with an optional $requestParams
+     *
+     * @param string $url
+     * @param array $requestParams
+     * @return string
+     */
+    public function delete($url, $requestParams = null)
+    {
+        return $this->request($url, 'DELETE', $requestParams);
+    }
+
+    /**
+     * Makes the 'GET' request to the $url with an optional $requestParams
+     *
+     * @param string $url
+     * @param array $requestParams
+     * @return string
+     */
+    public function get($url, $requestParams = null)
+    {
+        return $this->request($url, 'GET', $requestParams);
+    }
+
+    /**
+     * Returns the last transfer's response data
+     *
+     * @return string
+     */
+    public function getResponse()
+    {
+        return $this->response;
+    }
+
+    /**
+     * Gets the information about the last transfer
+     *
+     * If $key is given, returns its value. Otherwise, returns an associative array with the following elements:
+     * url                      - Last effective URL
+     * content_type             - Content-Type: of downloaded object, NULL indicates server did not send valid Content-Type: header
+     * http_code                - Last received HTTP code
+     * header_size              - Total size of all headers received
+     * request_size             - Total size of issued requests, currently only for HTTP requests
+     * filetime                 - Remote time of the retrieved document, if -1 is returned the time of the document is unknown
+     * ssl_verify_result        - Result of SSL certification verification requested by setting CURLOPT_SSL_VERIFYPEER
+     * redirect_count           - Number of redirects it went through if CURLOPT_FOLLOWLOCATION was set
+     * total_time               - Total transaction time in seconds for last transfer
+     * namelookup_time          - Time in seconds until name resolving was complete
+     * connect_time             - Time in seconds it took to establish the connection
+     * pretransfer_time         - Time in seconds from start until just before file transfer begins
+     * size_upload              - Total number of bytes uploaded
+     * size_download            - Total number of bytes downloaded
+     * speed_download           - Average download speed
+     * speed_upload             - Average upload speed
+     * download_content_length  - content-length of download, read from Content-Length:  field
+     * upload_content_length    - Specified size of upload
+     * starttransfer_time       - Time in seconds until the first byte is about to be transferred
+     * redirect_time            - Time in seconds of all redirection steps before final transaction was started
+     * certinfo                 - There is official description for this field yet
+     * request_header           - The request string sent. For this to work, add the CURLINFO_HEADER_OUT option
+     *
+     * @param string $key @see http://php.net/manual/en/function.curl-getinfo.php
+     * @throws CurlWrapperException
+     * @return array|string
+     */
+    public function getTransferInfo($key = null)
+    {
+        if (empty($this->transferInfo)) {
+            throw new CurlWrapperException('There is no transfer info. Did you do the request?');
+        }
+
+        if ($key === null) {
+            return $this->transferInfo;
+        }
+
+        if (isset($this->transferInfo[$key])) {
+            return $this->transferInfo[$key];
+        }
+
+        throw new CurlWrapperException('There is no such key: '.$key);
+    }
+
+    /**
+     * Makes the 'HEAD' request to the $url with an optional $requestParams
+     *
+     * @param string $url
+     * @param array $requestParams
+     * @return string
+     */
+    public function head($url, $requestParams = null)
+    {
+        return $this->request($url, 'HEAD', $requestParams);
+    }
+
+    /**
+     * Makes the 'POST' request to the $url with an optional $requestParams
+     *
+     * @param string $url
+     * @param array $requestParams
+     * @return string
+     */
+    public function post($url, $requestParams = null)
+    {
+        return $this->request($url, 'POST', $requestParams);
+    }
+
+    /**
+     * Makes the 'PUT' request to the $url with an optional $requestParams
+     *
+     * @param string $url
+     * @param array $requestParams
+     * @return string
+     */
+    public function put($url, $requestParams = null)
+    {
+        return $this->request($url, 'PUT', $requestParams);
+    }
+
+    /**
+     * Makes the 'POST' request to the $url with raw $data
+     * Use this method to send raw JSON, etc.
+     *
+     * @param string $url
+     * @param string $data
+     * @return string
+     */
+    public function rawPost($url, $data)
+    {
+        $this->prepareRawPayload($data);
+
+        return $this->request($url, 'RAW_POST');
+    }
+
+    /**
+     * Makes the 'PUT' request to the $url with raw $data
+     * Use this method to send raw JSON, etc.
+     *
+     * @param string $url
+     * @param string $data
+     * @return string
+     */
+    public function rawPut($url, $data)
+    {
+        $this->prepareRawPayload($data);
+
+        return $this->request($url, 'PUT');
+    }
+
+    /**
+     * Removes the cookie for next cURL transfer
+     *
+     * @param string $name Name of cookie
+     */
+    public function removeCookie($name)
+    {
+        if (isset($this->cookies[$name])) {
+            unset($this->cookies[$name]);
+        }
+    }
+
+    /**
+     * Removes the header for next cURL transfer
+     *
+     * @param string $header
+     */
+    public function removeHeader($header)
+    {
+        if (isset($this->headers[$header])) {
+            unset($this->headers[$header]);
+        }
+    }
+
+    /**
+     * Removes the option for next cURL transfer
+     *
+     * @param integer $option CURLOPT_XXX predefined constant
+     */
+    public function removeOption($option)
+    {
+        if (isset($this->options[$option])) {
+            unset($this->options[$option]);
+        }
+    }
+
+    /**
+     * Removes the request parameter for next cURL transfer
+     *
+     * @param string $name
+     */
+    public function removeRequestParam($name)
+    {
+        if (isset($this->requestParams[$name])) {
+            unset($this->requestParams[$name]);
+        }
+    }
+
+    /**
+     * Makes the request of the specified $method to the $url with an optional $requestParams
+     *
+     * @param string $url
+     * @param string $method
+     * @param array $requestParams
+     * @throws CurlWrapperCurlException
+     * @return string
+     */
+    public function request($url, $method = 'GET', $requestParams = null)
+    {
+        $this->setURL($url);
+        $this->setRequestMethod($method);
+
+        if (!empty($requestParams)) {
+            $this->addRequestParam($requestParams);
+        }
+
+        $this->initOptions();
+        $this->response = curl_exec($this->ch);
+
+        if ($this->response === false) {
+            throw new CurlWrapperCurlException($this->ch);
+        }
+
+        $this->transferInfo = curl_getinfo($this->ch);
+
+        return $this->response;
+    }
+
+    /**
+     * Reinitiates the cURL handle
+     * IMPORTANT: headers, options, request parameters, cookies and cookies file are remain untouched!
+     */
+    public function reset()
+    {
+        $this->__destruct();
+        $this->transferInfo = array();
+        $this->__construct();
+    }
+
+    /**
+     * Reinitiates the cURL handle and resets all data
+     * Including headers, options, request parameters, cookies and cookies file
+     */
+    public function resetAll()
+    {
+        $this->clearHeaders();
+        $this->clearOptions();
+        $this->clearRequestParams();
+        $this->clearCookies();
+        $this->clearCookieFile();
+        $this->reset();
+    }
+
+    /**
+     * Sets the number of seconds to wait while trying to connect, use 0 to wait indefinitely
+     *
+     * @param integer $seconds
+     */
+    public function setConnectTimeOut($seconds)
+    {
+        $this->addOption(CURLOPT_CONNECTTIMEOUT, $seconds);
+    }
+
+    /**
+     * Sets the filename to store cookies
+     *
+     * @param string $filename
+     * @throws CurlWrapperException
+     */
+    public function setCookieFile($filename)
+    {
+        if (!is_writable($filename)) {
+            throw new CurlWrapperException('Cookie file "'.$filename.'" is not writable or does\'n exists!');
+        }
+
+        $this->cookieFile = $filename;
+    }
+
+    /**
+     * Sets the default headers
+     */
+    public function setDefaultHeaders()
+    {
+        $this->headers = array(
+            'Accept'          => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+            'Accept-Charset'  => 'utf-8;q=0.7,*;q=0.7',
+            'Accept-Language' => 'en-US,en;q=0.8',
+            'Accept-Encoding' => 'gzip,deflate',
+            'Keep-Alive'      => '300',
+            'Connection'      => 'keep-alive',
+            'Cache-Control'   => 'max-age=0',
+            'Pragma'          => ''
+        );
+    }
+
+    /**
+     * Sets the default options
+     */
+    public function setDefaultOptions()
+    {
+        $this->options = array(
+            CURLOPT_RETURNTRANSFER => true,
+            CURLOPT_HEADER         => false,
+            CURLOPT_ENCODING       => 'gzip,deflate',
+            CURLOPT_AUTOREFERER    => true,
+            CURLOPT_CONNECTTIMEOUT => 15,
+            CURLOPT_TIMEOUT        => 30,
+        );
+    }
+
+    /**
+     * Sets default headers, options and user agent if $userAgent is given
+     *
+     * @param string $userAgent Some predefined user agent name (ie, firefox, opera, etc.) or any string you want
+     */
+    public function setDefaults($userAgent = null)
+    {
+        $this->setDefaultHeaders();
+        $this->setDefaultOptions();
+
+        if (!empty($userAgent)) {
+            $this->setUserAgent($userAgent);
+        } else {
+            $this->setUserAgent('chrome');
+        }
+    }
+
+    /**
+     * If $value is true sets CURLOPT_FOLLOWLOCATION option to follow any "Location: " header that the server
+     * sends as part of the HTTP header (note this is recursive, PHP will follow as many "Location: " headers
+     * that it is sent, unless CURLOPT_MAXREDIRS option is set).
+     *
+     * @param boolean $value
+     */
+    public function setFollowRedirects($value)
+    {
+        $this->addOption(CURLOPT_FOLLOWLOCATION, $value);
+    }
+
+    /**
+     * Sets the contents of the "Referer: " header to be used in a HTTP request
+     *
+     * @param string $referer
+     */
+    public function setReferer($referer)
+    {
+        $this->addOption(CURLOPT_REFERER, $referer);
+    }
+
+    /**
+     * Sets the maximum number of seconds to allow cURL functions to execute
+     *
+     * @param integer $seconds
+     */
+    public function setTimeout($seconds)
+    {
+        $this->addOption(CURLOPT_TIMEOUT, $seconds);
+    }
+
+    /**
+     * Sets the contents of the "User-Agent: " header to be used in a HTTP request
+     * You can use CurlWrapper's predefined shortcuts: 'ie', 'firefox', 'opera' and 'chrome'
+     *
+     * @param string $userAgent
+     */
+    public function setUserAgent($userAgent)
+    {
+        if (isset(self::$predefinedUserAgents[$userAgent])) {
+            $this->addOption(CURLOPT_USERAGENT, self::$predefinedUserAgents[$userAgent]);
+        } else {
+            $this->addOption(CURLOPT_USERAGENT, $userAgent);
+        }
+    }
+
+    /**
+     * Sets the HTTP Authentication type.
+     *
+     * Defaults to CURLAUTH_BASIC.
+     *
+     * @param int $type
+     */
+    public function setAuthType($type = CURLAUTH_BASIC) {
+        $this->addOption(CURLOPT_HTTPAUTH, $type);
+    }
+
+    /**
+     * Sets the username and password for HTTP Authentication.
+     *
+     * @param string $username
+     * @param string $password
+     */
+    public function setAuthCredentials($username, $password) {
+        $this->addOption(CURLOPT_USERPWD, "$username:$password");
+    }
+
+    /**
+     * Sets the value of cookieFile to empty string
+     */
+    public function unsetCookieFile()
+    {
+        $this->cookieFile = '';
+    }
+
+    /**
+     * Builds url from associative array produced by parse_str() function
+     *
+     * @param array $parsedUrl
+     * @return string
+     */
+    protected function buildUrl($parsedUrl)
+    {
+        return (isset($parsedUrl['scheme'])   ?     $parsedUrl["scheme"].'://' : '').
+               (isset($parsedUrl['user'])     ?     $parsedUrl["user"].':'     : '').
+               (isset($parsedUrl['pass'])     ?     $parsedUrl["pass"].'@'     : '').
+               (isset($parsedUrl['host'])     ?     $parsedUrl["host"]         : '').
+               (isset($parsedUrl['port'])     ? ':'.$parsedUrl["port"]         : '').
+               (isset($parsedUrl['path'])     ?     $parsedUrl["path"]         : '').
+               (isset($parsedUrl['query'])    ? '?'.$parsedUrl["query"]        : '').
+               (isset($parsedUrl['fragment']) ? '#'.$parsedUrl["fragment"]     : '');
+    }
+
+    /**
+     * Sets the final options and prepares request params, headers and cookies
+     *
+     * @throws CurlWrapperCurlException
+     */
+    protected function initOptions()
+    {
+        if (!empty($this->requestParams)) {
+            if (isset($this->options[CURLOPT_HTTPGET])) {
+                $this->prepareGetParams();
+            } else {
+                $this->addOption(CURLOPT_POSTFIELDS, http_build_query($this->requestParams));
+            }
+        }
+
+        if (!empty($this->headers)) {
+            $this->addOption(CURLOPT_HTTPHEADER, $this->prepareHeaders());
+        }
+
+        if (!empty($this->cookieFile)) {
+            $this->addOption(CURLOPT_COOKIEFILE, $this->cookieFile);
+            $this->addOption(CURLOPT_COOKIEJAR, $this->cookieFile);
+        }
+
+        if (!empty($this->cookies)) {
+            $this->addOption(CURLOPT_COOKIE, $this->prepareCookies());
+        }
+
+        if (!curl_setopt_array($this->ch, $this->options)) {
+            throw new CurlWrapperCurlException($this->ch);
+        }
+    }
+
+    /**
+     * Converts the cookies array to the correct string format
+     *
+     * @return string
+     */
+    protected function prepareCookies()
+    {
+        $cookiesString = '';
+
+        foreach ($this->cookies as $cookie => $value) {
+            $cookiesString .= $cookie.'='.$value.'; ';
+        }
+
+        return $cookiesString;
+    }
+
+    /**
+     * Converts request parameters to the query string and adds it to the request url
+     */
+    protected function prepareGetParams()
+    {
+        $parsedUrl = parse_url($this->options[CURLOPT_URL]);
+        $query = http_build_query($this->requestParams);
+
+        if (isset($parsedUrl['query'])) {
+            $parsedUrl['query'] .= '&'.$query;
+        } else {
+            $parsedUrl['query'] = $query;
+        }
+
+        $this->setUrl($this->buildUrl($parsedUrl));
+    }
+
+    /**
+     * Sets up options for POST/PUT request with raw $data
+     *
+     * @param string $data
+     */
+    protected function prepareRawPayload($data)
+    {
+        $this->clearRequestParams();
+        $this->addHeader('Content-Length', strlen($data));
+        $this->addOption(CURLOPT_POSTFIELDS, $data);
+    }
+
+    /**
+     * Converts the headers array to the cURL's option format array
+     *
+     * @return array
+     */
+    protected function prepareHeaders()
+    {
+        $headers = array();
+
+        foreach ($this->headers as $header => $value) {
+            $headers[] = $header.': '.$value;
+        }
+
+        return $headers;
+    }
+
+    /**
+     * Sets the HTTP request method
+     *
+     * @param string $method
+     */
+    protected function setRequestMethod($method)
+    {
+        // Preventing request methods collision
+        $this->removeOption(CURLOPT_NOBODY);
+        $this->removeOption(CURLOPT_HTTPGET);
+        $this->removeOption(CURLOPT_POST);
+        $this->removeOption(CURLOPT_CUSTOMREQUEST);
+
+        switch (strtoupper($method)) {
+            case 'HEAD':
+                $this->addOption(CURLOPT_NOBODY, true);
+            break;
+
+            case 'GET':
+                $this->addOption(CURLOPT_HTTPGET, true);
+            break;
+
+            case 'POST':
+                $this->addOption(CURLOPT_POST, true);
+            break;
+
+            case 'RAW_POST':
+                $this->addOption(CURLOPT_CUSTOMREQUEST, 'POST');
+            break;
+
+            default:
+                $this->addOption(CURLOPT_CUSTOMREQUEST, $method);
+        }
+    }
+
+    /**
+     * Sets the request url
+     *
+     * @param string $url Request URL
+     */
+    protected function setUrl($url)
+    {
+        $this->addOption(CURLOPT_URL, $url);
+    }
+}
+
+/**
+ * CurlWrapper Exceptions class
+ */
+class CurlWrapperException extends Exception
+{
+    /**
+     * @param string $message
+     */
+    public function __construct($message)
+    {
+        $this->message = $message;
+    }
+}
+
+/**
+ * CurlWrapper cURL Exceptions class
+ */
+class CurlWrapperCurlException extends CurlWrapperException
+{
+    /**
+     * @param resource $curlHandler
+     */
+    public function __construct($curlHandler)
+    {
+        $this->message = curl_error($curlHandler);
+        $this->code = curl_errno($curlHandler);
+    }
+}