Skip to content

Commit 00dc0e9

Browse files
committed
add store api
1 parent 2849455 commit 00dc0e9

File tree

13 files changed

+330
-37
lines changed

13 files changed

+330
-37
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
cmake_minimum_required(VERSION 3.19)
1+
cmake_minimum_required(VERSION 3.17)
22
project(developer_joyofenergy_cpp_beast)
33

44
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})

rest/configuration.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ constexpr auto ANDREAS_SMART_METER_ID = "smart-meter-3";
2121
constexpr auto ALEXS_SMART_METER_ID = "smart-meter-4";
2222

2323
std::vector<PricePlan> price_plans() {
24-
// todo
25-
// pricePlans.add(new PricePlan(MOST_EVIL_PRICE_PLAN_ID, "Dr Evil's Dark Energy", BigDecimal.TEN, emptyList()));
26-
// pricePlans.add(new PricePlan(RENEWABLES_PRICE_PLAN_ID, "The Green Eco", BigDecimal.valueOf(2), emptyList()));
27-
// pricePlans.add(new PricePlan(STANDARD_PRICE_PLAN_ID, "Power for Everyone", BigDecimal.ONE, emptyList()));
28-
return {};
24+
std::vector<PricePlan> pricePlans;
25+
pricePlans.push_back(PricePlan(MOST_EVIL_PRICE_PLAN_ID, DR_EVILS_DARK_ENERGY_ENERGY_SUPPLIER, 10, {}));
26+
pricePlans.push_back(PricePlan(RENEWABLES_PRICE_PLAN_ID, THE_GREEN_ECO_ENERGY_SUPPLIER, 2, {}));
27+
pricePlans.push_back(PricePlan(STANDARD_PRICE_PLAN_ID, POWER_FOR_EVERYONE_ENERGY_SUPPLIER, 1, {}));
28+
return pricePlans;
2929
}
3030

3131
std::unordered_map<std::string, std::string> smart_meter_to_price_plan_accounts() {

rest/controller/MeterReadingController.h

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22
#define DEVELOPER_JOYOFENERGY_CPP_BEAST_METERREADINGCONTROLLER_H
33

44
#include <service/ElectricityReadingService.h>
5+
#include <service/MeterReadingService.h>
56

67
#include <ctime>
78
#include <iomanip>
9+
#include <string>
810

911
#include <boost/beast/http.hpp>
1012
#include <nlohmann/json.hpp>
1113

14+
#include <iostream>
15+
1216
namespace http = boost::beast::http;
1317

1418
namespace detail {
@@ -27,12 +31,14 @@ namespace detail {
2731

2832
class MeterReadingController {
2933
public:
30-
MeterReadingController(ElectricityReadingService &meterReadingService) : meterReadingService(meterReadingService) {}
34+
MeterReadingController(ElectricityReadingService &electricityReadingService,
35+
MeterReadingService &meterReadingService) :
36+
electricityReadingService(electricityReadingService), meterReadingService(meterReadingService) {}
3137

3238
http::response<http::string_body>
3339
Read(const http::request<http::string_body> &req, const std::vector<std::string> &queries) {
3440
const auto &meterId = queries[0];
35-
auto readings = meterReadingService.GetReading(meterId);
41+
auto readings = electricityReadingService.GetReading(meterId);
3642

3743
if (!readings) {
3844
return {http::status::not_found, req.version()};
@@ -49,8 +55,29 @@ class MeterReadingController {
4955
return res;
5056
}
5157

58+
http::response<http::string_body>
59+
Store(const http::request<http::string_body> &req, const std::vector<std::string> &queries) {
60+
auto body = nlohmann::json::parse(req.body());
61+
auto smartMeterId = body["smartMeterId"];
62+
std::vector<ElectricityReading> electricityReadings;
63+
64+
for (auto &electricityReading : body["electricityReadings"]) {
65+
std::string tmp = electricityReading["time"];
66+
std::tm tm = {};
67+
std::stringstream ss(tmp);
68+
ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S");
69+
auto tp = std::chrono::system_clock::from_time_t(std::mktime(&tm));
70+
electricityReadings.emplace_back(tp, electricityReading["reading"]);
71+
}
72+
meterReadingService.storeReadings(smartMeterId, electricityReadings);
73+
74+
std::cout << electricityReadings.size() << std::endl;
75+
return {};
76+
}
77+
5278
private:
53-
ElectricityReadingService &meterReadingService;
79+
ElectricityReadingService &electricityReadingService;
80+
MeterReadingService &meterReadingService;
5481
};
5582

5683
#endif // DEVELOPER_JOYOFENERGY_CPP_BEAST_METERREADINGCONTROLLER_H
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#ifndef DEVELOPER_JOYOFENERGY_CPP_BEAST_PRICEPLANCOMPARATORCONTROLLER_H
2+
#define DEVELOPER_JOYOFENERGY_CPP_BEAST_PRICEPLANCOMPARATORCONTROLLER_H
3+
4+
#include <service/ElectricityReadingService.h>
5+
6+
#include <ctime>
7+
#include <iomanip>
8+
9+
#include <boost/beast/http.hpp>
10+
#include <nlohmann/json.hpp>
11+
12+
#include <service/PricePlanService.h>
13+
#include <iostream>
14+
15+
namespace http = boost::beast::http;
16+
17+
namespace price_detail {
18+
auto renderCostsAsJson(const ElectricityReading &r) {
19+
return nlohmann::json{{"hehe"},
20+
{"reading"}};
21+
}
22+
} // namespace price_detail
23+
24+
class PricePlanComparatorController {
25+
public:
26+
PricePlanComparatorController(PricePlanService &pricePlanService) : pricePlanService(pricePlanService) {}
27+
28+
// http::response<http::string_body>
29+
// Read(const http::request<http::string_body> &req, const std::vector<std::string> &queries) {
30+
// const auto &meterId = queries[0];
31+
// auto costs = pricePlanService.getConsumptionCostOfElectricityReadingsForEachPricePlan(meterId);
32+
// for(auto &i:*costs){
33+
// std::cout<<i.first<<" "<<i.second<<std::endl;
34+
// }
35+
//
36+
// if (!costs) {
37+
// return {http::status::not_found, req.version()};
38+
// }
39+
// http::response<http::string_body> res{http::status::ok, req.version()};
40+
// res.set(http::field::content_type, "application/json");
41+
// res.keep_alive(req.keep_alive());
42+
// auto results = nlohmann::json::array();
43+
// std::transform(costs->begin(), costs->end(), std::back_inserter(results), &price_detail::renderCostsAsJson);
44+
// nlohmann::json j;
45+
// j["readings"] = results;
46+
// res.body() = j.dump();
47+
// res.prepare_payload();
48+
// return res;
49+
// }
50+
51+
private:
52+
PricePlanService &pricePlanService;
53+
};
54+
55+
#endif //DEVELOPER_JOYOFENERGY_CPP_BEAST_PRICEPLANCOMPARATORCONTROLLER_H

rest/domain/MeterReadings.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef DEVELOPER_JOYOFENERGY_CPP_BEAST_METERREADINGS_H
2+
#define DEVELOPER_JOYOFENERGY_CPP_BEAST_METERREADINGS_H
3+
4+
#include <string>
5+
#include <list>
6+
7+
#include <domain/ElectricityReading.h>
8+
9+
class MeterReadings {
10+
public:
11+
MeterReadings() {}
12+
13+
MeterReadings(std::string smartMeterId, std::list<ElectricityReading> electricityReadings) :
14+
smartMeterId(smartMeterId), electricityReadings(electricityReadings) {};
15+
16+
std::list<ElectricityReading> getElectricityReadings() {
17+
return electricityReadings;
18+
}
19+
20+
std::string getSmartMeterId() {
21+
return smartMeterId;
22+
}
23+
24+
private:
25+
std::list<ElectricityReading> electricityReadings;
26+
std::string smartMeterId;
27+
};
28+
29+
#endif //DEVELOPER_JOYOFENERGY_CPP_BEAST_METERREADINGS_H

rest/domain/PricePlan.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,40 @@
11
#ifndef DEVELOPER_JOYOFENERGY_CPP_BEAST_PRICEPLAN_H
22
#define DEVELOPER_JOYOFENERGY_CPP_BEAST_PRICEPLAN_H
33

4+
#include <vector>
5+
#include <string>
6+
47
class PricePlan {
58
// todo:
9+
public:
10+
class PeakTimeMultiplier {
11+
enum DayOfWeek {
12+
MONDAY,
13+
TUESDAY,
14+
};
15+
16+
DayOfWeek dayOfWeek;
17+
int multiplier;
18+
19+
PeakTimeMultiplier(DayOfWeek dayOfWeek, int multiplier) : dayOfWeek(dayOfWeek), multiplier(multiplier) {}
20+
};
21+
22+
PricePlan(std::string planName, std::string energySupplier, int unitRate,
23+
std::vector<PeakTimeMultiplier> peakTimeMultipliers)
24+
: planName(planName), energySupplier(energySupplier), unitRate(unitRate),
25+
peakTimeMultipliers(peakTimeMultipliers) {}
26+
27+
const std::string &getEnergySupplier() const { return energySupplier; }
28+
29+
const std::string &getPlanName() const { return planName; }
30+
31+
const int getUnitRate() const { return unitRate; }
32+
33+
private:
34+
const std::string energySupplier;
35+
const std::string planName;
36+
const int unitRate; // unit price per kWh
37+
const std::vector<PeakTimeMultiplier> peakTimeMultipliers;
638
};
739

840
#endif // DEVELOPER_JOYOFENERGY_CPP_BEAST_PRICEPLAN_H

rest/server.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "server.h"
22

33
#include <controller/MeterReadingController.h>
4+
#include <controller/PricePlanComparatorController.h>
45

56
#include "configuration.h"
67
#include "listener.h"
@@ -11,7 +12,8 @@ namespace server_detail {
1112
public:
1213
explicit impl(int concurrency) : ioc(concurrency) {
1314
using reading = MeterReadingController;
14-
router.to<reading, &reading::Read>(R"(/readings/read/([a-zA-Z0-9_-]+))", readingService);
15+
router.to<reading, &reading::Read>(R"(/readings/read/([a-zA-Z0-9_-]+))", electricityReadingService, meterReadingService);
16+
router.to<reading, &reading::Store>(R"(/readings/store)", electricityReadingService, meterReadingService);
1517
}
1618

1719
void launch(const char *address, unsigned short port) {
@@ -27,7 +29,8 @@ namespace server_detail {
2729
private:
2830
boost::asio::io_context ioc;
2931
std::unordered_map<std::string, std::vector<ElectricityReading>> meterAssociatedReadings{readings()};
30-
ElectricityReadingService readingService{meterAssociatedReadings};
32+
ElectricityReadingService electricityReadingService{meterAssociatedReadings};
33+
MeterReadingService meterReadingService{meterAssociatedReadings};
3134
router router;
3235
std::function<http::response<http::string_body>(
3336
const http::request<http::string_body> &)> handler = router.handler();

rest/service/MeterReadingService.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//
2+
// Created by Cenxi Zhang on 2021/8/18.
3+
//
4+
5+
#ifndef DEVELOPER_JOYOFENERGY_CPP_BEAST_METERREADINGSERVICE_H
6+
#define DEVELOPER_JOYOFENERGY_CPP_BEAST_METERREADINGSERVICE_H
7+
8+
#include <map>
9+
#include <vector>
10+
#include <optional>
11+
#include <string>
12+
#include <domain/ElectricityReading.h>
13+
14+
#include <iostream>
15+
16+
class MeterReadingService {
17+
public:
18+
std::optional<std::vector<ElectricityReading>> getReadings(std::string smartMeterId) {
19+
if (meterAssociatedReadings.find(smartMeterId) == meterAssociatedReadings.end()) {
20+
return {};
21+
}
22+
return meterAssociatedReadings[smartMeterId];
23+
}
24+
25+
void storeReadings(std::string smartMeterId, std::vector<ElectricityReading> electricityReadings) {
26+
if (meterAssociatedReadings.find(smartMeterId) == meterAssociatedReadings.end()) {
27+
meterAssociatedReadings[smartMeterId] = {};
28+
}
29+
meterAssociatedReadings[smartMeterId].insert(meterAssociatedReadings[smartMeterId].end(),
30+
electricityReadings.begin(), electricityReadings.end());
31+
32+
std::cout<<meterAssociatedReadings.size()<<std::endl;
33+
}
34+
35+
MeterReadingService(std::unordered_map<std::string, std::vector<ElectricityReading>> meterAssociatedReadings) :
36+
meterAssociatedReadings(meterAssociatedReadings) {}
37+
38+
private:
39+
std::unordered_map<std::string, std::vector<ElectricityReading>> meterAssociatedReadings;
40+
};
41+
42+
#endif //DEVELOPER_JOYOFENERGY_CPP_BEAST_METERREADINGSERVICE_H

rest/service/PricePlanService.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#ifndef DEVELOPER_JOYOFENERGY_CPP_BEAST_PRICEPLANSERVICE_H
2+
#define DEVELOPER_JOYOFENERGY_CPP_BEAST_PRICEPLANSERVICE_H
3+
4+
#include <domain/ElectricityReading.h>
5+
#include <domain/PricePlan.h>
6+
#include <service/MeterReadingService.h>
7+
#include <vector>
8+
#include <ctime>
9+
#include <optional>
10+
#include <map>
11+
#include <string>
12+
#include <configuration.h>
13+
14+
class PricePlanService {
15+
public:
16+
using time_point_type = std::chrono::time_point<std::chrono::system_clock>;
17+
18+
std::optional<std::map<std::string, float>> getConsumptionCostOfElectricityReadingsForEachPricePlan(std::string smartMeterId){
19+
std::optional<std::vector<ElectricityReading>> electricityReadings = meterReadingService.getReadings(smartMeterId);
20+
if (!electricityReadings.has_value()) {
21+
return {};
22+
}
23+
24+
std::map<std::string, float> consumptionCostOfElectricityReadingsForEachPricePlan;
25+
for(auto pricePlan:pricePlans){
26+
consumptionCostOfElectricityReadingsForEachPricePlan.insert(std::make_pair(pricePlan.getPlanName(), calculateCost(electricityReadings.value(), pricePlan)));
27+
}
28+
return consumptionCostOfElectricityReadingsForEachPricePlan;
29+
}
30+
31+
PricePlanService(std::vector<PricePlan> pricePlans, MeterReadingService meterReadingService) :
32+
pricePlans(pricePlans), meterReadingService(meterReadingService) {}
33+
34+
private:
35+
const std::vector<PricePlan> pricePlans;
36+
MeterReadingService meterReadingService;
37+
38+
int calculateCost(std::vector<ElectricityReading> electricityReadings, PricePlan pricePlan) {
39+
float average = calculateAverageReading(electricityReadings);
40+
float timeElapsed = calculateTimeElapsed(electricityReadings);
41+
42+
float averagedCost = round(average / timeElapsed);
43+
return averagedCost * pricePlan.getUnitRate();
44+
}
45+
46+
float calculateAverageReading(std::vector<ElectricityReading> electricityReadings) {
47+
float summedReadings = 0;
48+
for (ElectricityReading electricityReading : electricityReadings) {
49+
summedReadings += electricityReading.getReading();
50+
}
51+
52+
return round(summedReadings / electricityReadings.size());
53+
}
54+
55+
float calculateTimeElapsed(std::vector<ElectricityReading> electricityReadings) {
56+
ElectricityReading first = *electricityReadings.begin();
57+
ElectricityReading last = *electricityReadings.begin();
58+
std::vector<ElectricityReading>::iterator it;
59+
for(it = electricityReadings.begin(); it != electricityReadings.end(); it++){
60+
if (it->getTime() < first.getTime()){
61+
first = *it;
62+
}
63+
if (it->getTime() > first.getTime()){
64+
last = *it;
65+
}
66+
}
67+
68+
std::chrono::steady_clock::duration duration = std::chrono::duration_cast<std::chrono::hours>(
69+
last.getTime() - first.getTime());
70+
return duration.count();
71+
}
72+
};
73+
74+
#endif // DEVELOPER_JOYOFENERGY_CPP_BEAST_PRICEPLANSERVICE_H

test/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
add_executable(endpoint_test)
2-
target_sources(endpoint_test PRIVATE readings.cpp)
2+
target_sources(endpoint_test PRIVATE ReadingTest.cpp)
33
find_package(GTest REQUIRED)
44
find_package(nlohmann_json REQUIRED)
55
target_link_libraries(endpoint_test PRIVATE GTest::gmock_main nlohmann_json::nlohmann_json rest)

0 commit comments

Comments
 (0)