diff --git a/install/data/carbon_intensity/carbon-intensity-electricity.txt b/install/data/carbon_intensity/carbon-intensity-electricity.txt new file mode 100644 index 00000000..a776620c --- /dev/null +++ b/install/data/carbon_intensity/carbon-intensity-electricity.txt @@ -0,0 +1,2 @@ +Data source: +https://ourworldindata.org/grapher/carbon-intensity-electricity \ No newline at end of file diff --git a/install/mysql/plugin_carbon_empty.sql b/install/mysql/plugin_carbon_empty.sql index da2f1360..5e49106c 100644 --- a/install/mysql/plugin_carbon_empty.sql +++ b/install/mysql/plugin_carbon_empty.sql @@ -132,17 +132,51 @@ CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_computerusageprofiles` ( CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_embodiedimpacts` ( `id` int unsigned NOT NULL AUTO_INCREMENT, - `itemtype` varchar(255) DEFAULT NULL, + `itemtype` varchar(255) DEFAULT NULL, `items_id` int unsigned NOT NULL DEFAULT '0', - `engine` varchar(255) DEFAULT NULL, - `engine_version` varchar(255) DEFAULT NULL, - `date_mod` timestamp NULL DEFAULT NULL, - `gwp` float unsigned DEFAULT '0' COMMENT '(unit gCO2eq) Global warming potential', + `engine` varchar(255) DEFAULT NULL, + `engine_version` varchar(255) DEFAULT NULL, + `date_mod` timestamp NULL DEFAULT NULL, + `gwp` float unsigned DEFAULT '0' COMMENT '(unit gCO2eq) Global warming potential', `gwp_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', - `adp` float unsigned DEFAULT '0' COMMENT '(unit gSbeq) Abiotic depletion potential', + `adp` float unsigned DEFAULT '0' COMMENT '(unit gSbeq) Abiotic depletion potential', `adp_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', - `pe` float unsigned DEFAULT '0' COMMENT '(unit J) Primary energy', + `pe` float unsigned DEFAULT '0' COMMENT '(unit J) Primary energy', `pe_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `gwppb` float unsigned DEFAULT '0' COMMENT '(unit g CO2 eq) Climate change - Contribution of biogenic emissions', + `gwppb_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `gwppf` float unsigned DEFAULT '0' COMMENT '(unit g CO2 eq) Climate change - Contribution of fossil fuel emissions', + `gwppf_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `gwpplu` float unsigned DEFAULT '0' COMMENT '(unit g CO2 eq) Climate change - Contribution of emissions from land use change', + `gwpplu_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `ir` float unsigned DEFAULT '0' COMMENT '(unit g U235 eq) Emissions of radionizing substances', + `ir_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `lu` float unsigned DEFAULT '0' COMMENT '(unit none) Land use', + `lu_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `odp` float unsigned DEFAULT '0' COMMENT '(unit g CFC-11 eq) Depletion of the ozone layer', + `odp_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `pm` float unsigned DEFAULT '0' COMMENT '(unit Disease occurrence) Fine particle emissions', + `pm_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `pocp` float unsigned DEFAULT '0' COMMENT '(unit g NMVOC eq) Photochemical ozone formation', + `pocp_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `wu` float unsigned DEFAULT '0' COMMENT '(unit L) Use of water resources', + `wu_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `mips` float unsigned DEFAULT '0' COMMENT '(unit g) Material input per unit of service', + `mips_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `adpe` float unsigned DEFAULT '0' COMMENT '(unit g SB eq) Use of mineral and metal resources', + `adpe_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `adpf` float unsigned DEFAULT '0' COMMENT '(unit J) Use of fossil resources (including nuclear)', + `adpf_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `ap` float unsigned DEFAULT '0' COMMENT '(unit mol H+ eq) Acidification', + `ap_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `ctue` float unsigned DEFAULT '0' COMMENT '(unit CTUe) Freshwater ecotoxicity', + `ctue_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `epf` float unsigned DEFAULT '0' COMMENT '(unit g P eq) Eutrophication of freshwater', + `epf_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `epm` float unsigned DEFAULT '0' COMMENT '(unit g N eq) Eutrophication of marine waters', + `epm_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `ept` float unsigned DEFAULT '0' COMMENT '(unit mol N eq) Terrestrial eutrophication', + `ept_quality` int unsigned NOT NULL DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', PRIMARY KEY (`id`), UNIQUE KEY `unicity` (`itemtype`, `items_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; @@ -161,12 +195,12 @@ CREATE TABLE IF NOT EXISTS `glpi_plugin_carbon_monitormodels` ( `gwp` int DEFAULT '0' COMMENT '(unit gCO2eq) Global warming potential', `gwp_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', `gwp_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', - `adp` int DEFAULT '0' COMMENT '(unit gSbEq) Abiotic depletion potential', - `adp_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', - `adp_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', - `pe` int DEFAULT '0' COMMENT '(unit J) Primary energy', - `pe_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', - `pe_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `adp` int DEFAULT '0' COMMENT '(unit gSbEq) Abiotic depletion potential', + `adp_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `adp_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', + `pe` int DEFAULT '0' COMMENT '(unit J) Primary energy', + `pe_source` mediumtext DEFAULT NULL COMMENT 'any information to describe the source, URL preferred', + `pe_quality` int DEFAULT '0' COMMENT 'DataTtacking\\AbstractTracked::DATA_QUALITY_* constants', PRIMARY KEY (`id`), UNIQUE KEY `unicity` (`monitormodels_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/src/Impact/Embodied/Boavizta/AbstractAsset.php b/src/Impact/Embodied/Boavizta/AbstractAsset.php index f6db53a6..f215f3dc 100644 --- a/src/Impact/Embodied/Boavizta/AbstractAsset.php +++ b/src/Impact/Embodied/Boavizta/AbstractAsset.php @@ -55,6 +55,30 @@ abstract class AbstractAsset extends AbstractEmbodiedImpact implements AssetInte /** @var Client instance of the HTTP client */ protected ?Client $client = null; + protected array $criterias = [ + 'gwp' => 1000, // Kg + 'adp' => 1000, // Kg + 'pe' => 1000000, // MJ + 'gwppb' => 1000, // Kg + 'gwppf' => 1000, // Kg + 'gwpplu' => 1000, // Kg + 'ir' => 1000, // Kg + 'lu' => 1, // (no unit) + 'odp' => 1000, // Kg + 'pm' => 1, // (no unit) + 'pocp' => 1000, // Kg + 'wu' => 1000, // M^3 + 'mips' => 1000, // Kg + 'adpe' => 1000, // Kg + 'adpf' => 1000000, // MJ + 'ap' => 1, // mol + 'ctue' => 1, // CTUe + // 'ctuh_c' => '', // CTUh request fails when this criteria is added, not a URL encoding issue + 'epf' => 1000, // Kg + 'epm' => 1000, // Kg + 'ept' => 1, // mol + ]; + // abstract public static function getEngine(CommonDBTM $item): EngineInterface; /** @@ -98,7 +122,23 @@ protected function getVersion(): string return self::$engine_version; } - protected function query($description): array + /** + * Get the quety string specifying the impact criterias for the HTTP request + * + * @return string + */ + protected function getCriteriasQueryString(): string + { + return 'criteria=' . implode('&criteria=', array_keys($this->criterias)); + } + + /** + * Send a HTTP query + * + * @param array $description + * @return array + */ + protected function query(array $description): array { try { $response = $this->client->post($this->endpoint, [ @@ -115,6 +155,7 @@ protected function query($description): array /** * Read the response to find the impacts provided by Boaviztapi * + * @param array $response * @return array */ protected function parseResponse(array $response): array @@ -130,22 +171,73 @@ protected function parseResponse(array $response): array if ($impact_id === false) { continue; } - switch ($type) { - case 'gwp': - $impacts[$impact_id] = $this->parseGwp($response['impacts'][$type]); - break; - case 'adp': - $impacts[$impact_id] = $this->parseAdp($response['impacts'][$type]); - break; - case 'pe': - $impacts[$impact_id] = $this->parsePe($response['impacts'][$type]); - break; - } + $impacts[$impact_id] = $this->parseCriteria($type, $response['impacts'][$type]); + // switch ($type) { + // case 'gwp': + // $impacts[$impact_id] = $this->parseGwp($response['impacts'][$type]); + // break; + // case 'adp': + // $impacts[$impact_id] = $this->parseAdp($response['impacts'][$type]); + // break; + // case 'pe': + // $impacts[$impact_id] = $this->parsePe($response['impacts'][$type]); + // break; + // case 'gwppb': + // break; + // case 'gwppf': + // break; + // case 'gwpplu': + // break; + // case 'ir': + // break; + // case 'lu': + // break; + // case 'odp': + // break; + // case 'pm': + // break; + // case 'pocp': + // break; + // case 'wu': + // break; + // case 'mips': + // break; + // case 'adpe': + // break; + // case 'adpf': + // break; + // case 'ap': + // break; + // case 'ctue': + // break; + // case 'epf': + // break; + // case 'epm': + // break; + // case 'ept': + // break; + // } } return $impacts; } + protected function parseCriteria(string $name, array $impact): ?TrackedFloat + { + if ($impact['embedded'] === 'not implemented') { + return null; + } + + $unit_multiplier = $this->criterias[$name]; + $value = new TrackedFloat( + $impact['embedded']['value'] * $unit_multiplier, + null, + TrackedFloat::DATA_QUALITY_ESTIMATED + ); + + return $value; + } + protected function parseGwp(array $impact): ?TrackedFloat { if ($impact['embedded'] === 'not implemented') { diff --git a/src/Impact/Embodied/Boavizta/Computer.php b/src/Impact/Embodied/Boavizta/Computer.php index f395664e..12e6e4b8 100644 --- a/src/Impact/Embodied/Boavizta/Computer.php +++ b/src/Impact/Embodied/Boavizta/Computer.php @@ -59,6 +59,7 @@ protected function doEvaluation(): ?array // adapt $this->endpoint depending on the type of computer (server, laptop, ...) $type = $this->getType($this->item); $this->endpoint = $this->getEndpoint($type); + $this->endpoint .= '?' . $this->getCriteriasQueryString(); // Ask for embodied impact only $handle_hardware = in_array($type, [ diff --git a/src/Impact/Embodied/Engine.php b/src/Impact/Embodied/Engine.php index 7a3a2dbb..c033983f 100644 --- a/src/Impact/Embodied/Engine.php +++ b/src/Impact/Embodied/Engine.php @@ -131,6 +131,8 @@ protected static function configureEngine(EmbodiedImpactInterface $engine): Embo */ private static function hasModelData(CommonDBTM $item): bool { + global $DB; + $itemtype = get_class($item); $glpi_model_class = $itemtype . 'Model'; $glpi_model_class_fk = getForeignKeyFieldForItemType($glpi_model_class); @@ -138,12 +140,16 @@ private static function hasModelData(CommonDBTM $item): bool * @var class-string $model_class */ $model_class = 'GlpiPlugin\\Carbon\\' . $glpi_model_class; + $model_table = getTableForItemType($model_class); $glpi_model_id = $item->fields[$glpi_model_class_fk]; $crit = [ $glpi_model_class_fk => $glpi_model_id ]; $types = Type::getImpactTypes(); foreach ($types as $key => $type) { + if (!$DB->fieldExists($model_table, $type)) { + continue; + } $crit['OR'][] = [ $type . '_quality' => ['<>', AbstractTracked::DATA_QUALITY_UNSET_VALUE] ]; diff --git a/src/Impact/Type.php b/src/Impact/Type.php index 7c3f5551..7a9de684 100644 --- a/src/Impact/Type.php +++ b/src/Impact/Type.php @@ -35,14 +35,50 @@ class Type { - const IMPACT_GWP = 0; // Global warming potential - const IMPACT_ADP = 1; // Abiotic Depletion Potential - const IMPACT_PE = 2; // Primary Energy + const IMPACT_GWP = 0; // Global warming potential + const IMPACT_ADP = 1; // Abiotic Depletion Potential + const IMPACT_PE = 3; // Primary Energy + const IMPACT_GWPPB = 4; + const IMPACT_GWPPF = 5; + const IMPACT_GWPPLU = 6; + const IMPACT_IR = 7; + const IMPACT_LU = 8; + const IMPACT_ODP = 9; + const IMPACT_PM = 10; + const IMPACT_POCP = 11; + const IMPACT_WU = 12; + const IMPACT_MIPS = 13; + const IMPACT_ADPE = 14; + const IMPACT_ADPF = 15; + const IMPACT_AP = 16; + const IMPACT_CTUE = 17; + // const IMPACT_CTUHC = 18; + const IMPACT_EPF = 19; + const IMPACT_EPM = 20; + const IMPACT_EPT = 21; private static array $impact_types = [ - self::IMPACT_GWP => 'gwp', - self::IMPACT_ADP => 'adp', - self::IMPACT_PE => 'pe', + self::IMPACT_GWP => 'gwp', + self::IMPACT_ADP => 'adp', + self::IMPACT_PE => 'pe', + self::IMPACT_GWPPB => 'gwppb', + self::IMPACT_GWPPF => 'gwppf', + self::IMPACT_GWPPLU => 'gwpplu', + self::IMPACT_IR => 'ir', + self::IMPACT_LU => 'lu', + self::IMPACT_ODP => 'odp', + self::IMPACT_PM => 'pm', + self::IMPACT_POCP => 'pocp', + self::IMPACT_WU => 'wu', + self::IMPACT_MIPS => 'mips', + self::IMPACT_ADPE => 'adpe', + self::IMPACT_ADPF => 'adpf', + self::IMPACT_AP => 'ap', + self::IMPACT_CTUE => 'ctue', + // self::IMPACT_CTUHC => 'ctuh_c', + self::IMPACT_EPF => 'epf', + self::IMPACT_EPM => 'epm', + self::IMPACT_EPT => 'ept', ]; public static function getImpactTypes(): array