smartplant 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/comingsoon.js +6 -0
- package/package.json +109 -111
- package/index.js +0 -314
package/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
SmartPlant README
|
|
2
1
|
|
|
3
2
|
# SmartPlant
|
|
4
3
|
|
|
4
|
+

|
|
5
|
+
|
|
5
6
|
**SmartPlant** is a pioneering library designed for plant care with AI technology, aimed at integrating automated alerts with multi-language support. This standard prototype library is crafted for intelligent devices that manage plant care, enhancing the level of interaction and intelligence between plants and their owners. The core idea behind SmartPlant is to pave the way for advancements in plant care technology. It serves as a foundation for developing more sophisticated solutions and experimenting with innovative devices that cater to the needs of plants. By leveraging this library, developers can contribute to evolving the ecosystem of smart plant care.
|
|
6
7
|
|
|
7
8
|
## Features
|
package/comingsoon.js
ADDED
package/package.json
CHANGED
|
@@ -1,116 +1,114 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
},
|
|
42
|
-
"funding": {
|
|
2
|
+
"name": "smartplant",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "A library for managing plant care with alerts and multi-language support.",
|
|
5
|
+
"main": "comingsoon.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@serialport/parser-readline": "^12.0.0",
|
|
9
|
+
"axios": "^1.7.7",
|
|
10
|
+
"chalk": "^5.3.0",
|
|
11
|
+
"enquirer": "^2.4.1",
|
|
12
|
+
"nodemailer": "^6.9.15",
|
|
13
|
+
"readline": "^1.3.0",
|
|
14
|
+
"serialport": "^12.0.0"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"plant",
|
|
18
|
+
"care",
|
|
19
|
+
"alerts",
|
|
20
|
+
"multi-language",
|
|
21
|
+
"smart",
|
|
22
|
+
"AI",
|
|
23
|
+
"intelligence",
|
|
24
|
+
"npm",
|
|
25
|
+
"library"
|
|
26
|
+
],
|
|
27
|
+
"author": "Alejo Malia <alejomalia@gmail.com>",
|
|
28
|
+
"files": [
|
|
29
|
+
"./README.md"
|
|
30
|
+
],
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public",
|
|
33
|
+
"registry": "https://registry.npmjs.org/"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/pigeonposse/smartplant",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/pigeonposse/smartplant"
|
|
39
|
+
},
|
|
40
|
+
"funding": {
|
|
43
41
|
"type": "individual",
|
|
44
42
|
"url": "https://pigeonposse.com/?popup=donate"
|
|
43
|
+
},
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/pigeonposse/smartplant/issues",
|
|
46
|
+
"email": "dev@pigeonposse.com"
|
|
47
|
+
},
|
|
48
|
+
"license": "GPL-3.0",
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@backan/builder": "0.0.16",
|
|
51
|
+
"@changesets/changelog-github": "0.5.0",
|
|
52
|
+
"@changesets/cli": "2.27.8",
|
|
53
|
+
"@commitlint/cli": "19.5.0",
|
|
54
|
+
"@pigeon-posse/eslint-config": "1.0.1",
|
|
55
|
+
"@typescript-eslint/eslint-plugin": "8.2.0",
|
|
56
|
+
"@typescript-eslint/parser": "8.2.0",
|
|
57
|
+
"commitizen": "4.3.0",
|
|
58
|
+
"commitlint-config-gitmoji": "2.3.1",
|
|
59
|
+
"cz-customizable": "7.2.1",
|
|
60
|
+
"cz-emoji": "1.3.2-canary.2",
|
|
61
|
+
"eslint": "8.57.0",
|
|
62
|
+
"git-cz": "4.9.0",
|
|
63
|
+
"eslint-plugin-align-assignments": "1.1.2",
|
|
64
|
+
"eslint-plugin-align-import": "1.0.0",
|
|
65
|
+
"eslint-plugin-canonical": "5.0.0",
|
|
66
|
+
"eslint-plugin-html": "7.1.0",
|
|
67
|
+
"eslint-plugin-import": "2.29.1",
|
|
68
|
+
"eslint-plugin-jsdoc": "46.10.1",
|
|
69
|
+
"eslint-plugin-json": "3.1.0",
|
|
70
|
+
"eslint-plugin-jsonc": "2.13.0",
|
|
71
|
+
"eslint-plugin-markdownlint": "0.5.0",
|
|
72
|
+
"eslint-plugin-package-json": "0.12.2",
|
|
73
|
+
"eslint-plugin-promise": "6.1.1",
|
|
74
|
+
"eslint-plugin-yaml": "0.5.0",
|
|
75
|
+
"typescript": "5.6.2",
|
|
76
|
+
"vite": "^5.4.4"
|
|
77
|
+
},
|
|
78
|
+
"commitlint": {
|
|
79
|
+
"extends": [
|
|
80
|
+
"gitmoji"
|
|
81
|
+
],
|
|
82
|
+
"rules": {
|
|
83
|
+
"header-max-length": [
|
|
84
|
+
0,
|
|
85
|
+
"always",
|
|
86
|
+
100
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"config": {
|
|
91
|
+
"commitizen": {
|
|
92
|
+
"path": "./node_modules/cz-customizable"
|
|
45
93
|
},
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
"email": "dev@pigeonposse.com"
|
|
49
|
-
},
|
|
50
|
-
"scripts": {
|
|
51
|
-
"start": "node index.js",
|
|
52
|
-
"update-version": "changeset && changeset version",
|
|
53
|
-
"push": "git add . && cz && git push -f origin $@",
|
|
54
|
-
"push:main": "pnpm push main"
|
|
55
|
-
},
|
|
56
|
-
"license": "GPL-3.0",
|
|
57
|
-
"devDependencies": {
|
|
58
|
-
"@backan/builder": "0.0.16",
|
|
59
|
-
"@changesets/changelog-github": "0.5.0",
|
|
60
|
-
"@changesets/cli": "2.27.8",
|
|
61
|
-
"@commitlint/cli": "19.5.0",
|
|
62
|
-
"@pigeon-posse/eslint-config": "1.0.1",
|
|
63
|
-
"@typescript-eslint/eslint-plugin": "8.2.0",
|
|
64
|
-
"@typescript-eslint/parser": "8.2.0",
|
|
65
|
-
"commitizen": "4.3.0",
|
|
66
|
-
"commitlint-config-gitmoji": "2.3.1",
|
|
67
|
-
"cz-customizable": "7.2.1",
|
|
68
|
-
"cz-emoji": "1.3.2-canary.2",
|
|
69
|
-
"eslint": "8.57.0",
|
|
70
|
-
"git-cz": "4.9.0",
|
|
71
|
-
"eslint-plugin-align-assignments": "1.1.2",
|
|
72
|
-
"eslint-plugin-align-import": "1.0.0",
|
|
73
|
-
"eslint-plugin-canonical": "5.0.0",
|
|
74
|
-
"eslint-plugin-html": "7.1.0",
|
|
75
|
-
"eslint-plugin-import": "2.29.1",
|
|
76
|
-
"eslint-plugin-jsdoc": "46.10.1",
|
|
77
|
-
"eslint-plugin-json": "3.1.0",
|
|
78
|
-
"eslint-plugin-jsonc": "2.13.0",
|
|
79
|
-
"eslint-plugin-markdownlint": "0.5.0",
|
|
80
|
-
"eslint-plugin-package-json": "0.12.2",
|
|
81
|
-
"eslint-plugin-promise": "6.1.1",
|
|
82
|
-
"eslint-plugin-yaml": "0.5.0",
|
|
83
|
-
"typescript": "5.6.2",
|
|
84
|
-
"vite": "^5.4.4"
|
|
85
|
-
},
|
|
86
|
-
"commitlint": {
|
|
87
|
-
"extends": [
|
|
88
|
-
"gitmoji"
|
|
89
|
-
],
|
|
90
|
-
"rules": {
|
|
91
|
-
"header-max-length": [
|
|
92
|
-
0,
|
|
93
|
-
"always",
|
|
94
|
-
100
|
|
95
|
-
]
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
|
-
"config": {
|
|
99
|
-
"commitizen": {
|
|
100
|
-
"path": "./node_modules/cz-customizable"
|
|
101
|
-
},
|
|
102
|
-
"cz-customizable": {
|
|
103
|
-
"config": ".dev/cz-config.cjs"
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
"extra": {
|
|
107
|
-
"scopes": [
|
|
108
|
-
{
|
|
109
|
-
"name": "lib"
|
|
110
|
-
},
|
|
111
|
-
{
|
|
112
|
-
"name": "all"
|
|
113
|
-
}
|
|
114
|
-
]
|
|
94
|
+
"cz-customizable": {
|
|
95
|
+
"config": ".dev/cz-config.cjs"
|
|
115
96
|
}
|
|
116
|
-
}
|
|
97
|
+
},
|
|
98
|
+
"extra": {
|
|
99
|
+
"scopes": [
|
|
100
|
+
{
|
|
101
|
+
"name": "lib"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"name": "all"
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
"scripts": {
|
|
109
|
+
"start": "node index.js",
|
|
110
|
+
"update-version": "changeset && changeset version",
|
|
111
|
+
"push": "git add . && cz && git push -f origin $@",
|
|
112
|
+
"push:main": "pnpm push main"
|
|
113
|
+
}
|
|
114
|
+
}
|
package/index.js
DELETED
|
@@ -1,314 +0,0 @@
|
|
|
1
|
-
import { execSync } from 'child_process';
|
|
2
|
-
import { prompt } from 'enquirer';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import fs from 'fs'
|
|
5
|
-
import { fileURLToPath } from 'url';
|
|
6
|
-
import { dirname } from 'path';
|
|
7
|
-
|
|
8
|
-
// Get the directory name of the current module
|
|
9
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
-
const __dirname = dirname(__filename);
|
|
11
|
-
// Load messages based on selected language
|
|
12
|
-
function loadMessages(language) {
|
|
13
|
-
const languageFile = path.join(__dirname, `language/messages-${language}.json`);
|
|
14
|
-
try {
|
|
15
|
-
return JSON.parse(fs.readFileSync(languageFile, 'utf8'));
|
|
16
|
-
} catch (error) {
|
|
17
|
-
console.error(`Error loading language file: ${error.message}`);
|
|
18
|
-
return JSON.parse(fs.readFileSync(path.join(__dirname, 'language/messages-en.json'), 'utf8')); // Fallback to English
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
class PlantInfoGenerator {
|
|
23
|
-
async generatePlantInfo(name, type) {
|
|
24
|
-
try {
|
|
25
|
-
const info = await this.fetchInfoFromAI(name, type);
|
|
26
|
-
return info;
|
|
27
|
-
} catch (error) {
|
|
28
|
-
console.error(`Error generating plant info: ${error.message}`);
|
|
29
|
-
return {
|
|
30
|
-
description: 'No description available.',
|
|
31
|
-
characteristics: 'No characteristics available.',
|
|
32
|
-
moisture: { ideal: 50, min: 30, max: 70 },
|
|
33
|
-
light: { ideal: 500, min: 200, max: 800 },
|
|
34
|
-
temperature: { ideal: 22, min: 15, max: 30 }
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async fetchInfoFromAI(name, type) {
|
|
40
|
-
// Simulated AI response. Replace with actual AI interaction or API call.
|
|
41
|
-
return new Promise((resolve) => {
|
|
42
|
-
setTimeout(() => {
|
|
43
|
-
const info = {
|
|
44
|
-
description: `The ${name} is a ${type === 'indoor' ? 'popular indoor' : 'common outdoor'} plant, known for its ${type === 'indoor' ? 'air-purifying qualities' : 'resilience to various weather conditions'}.`,
|
|
45
|
-
characteristics: `${name} typically has ${type === 'indoor' ? 'glossy, dark green leaves' : 'vibrant flowers and sturdy stems'}. It's ${type === 'indoor' ? 'well-suited for low-light environments' : 'adaptable to different soil types'}.`,
|
|
46
|
-
moisture: {
|
|
47
|
-
ideal: type === 'indoor' ? 60 : 40,
|
|
48
|
-
min: type === 'indoor' ? 40 : 20,
|
|
49
|
-
max: type === 'indoor' ? 80 : 60
|
|
50
|
-
},
|
|
51
|
-
light: {
|
|
52
|
-
ideal: type === 'indoor' ? 400 : 700,
|
|
53
|
-
min: type === 'indoor' ? 200 : 500,
|
|
54
|
-
max: type === 'indoor' ? 600 : 900
|
|
55
|
-
},
|
|
56
|
-
temperature: {
|
|
57
|
-
ideal: type === 'indoor' ? 22 : 25,
|
|
58
|
-
min: type === 'indoor' ? 18 : 15,
|
|
59
|
-
max: type === 'indoor' ? 26 : 35
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
resolve(info);
|
|
63
|
-
}, 1000);
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
class SmartPlant {
|
|
69
|
-
constructor() {
|
|
70
|
-
this.apiKey = null;
|
|
71
|
-
this.plantType = null;
|
|
72
|
-
this.plantName = '';
|
|
73
|
-
this.alerts = {};
|
|
74
|
-
this.language = 'en';
|
|
75
|
-
this.messages = null;
|
|
76
|
-
this.sensors = {
|
|
77
|
-
moisture: null,
|
|
78
|
-
light: null,
|
|
79
|
-
temperature: null
|
|
80
|
-
};
|
|
81
|
-
this.plantInfo = null;
|
|
82
|
-
this.plantInfoGenerator = new PlantInfoGenerator();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async init() {
|
|
86
|
-
this.messages = loadMessages(this.language);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async setLanguage(language) {
|
|
90
|
-
this.language = language;
|
|
91
|
-
this.messages = loadMessages(this.language);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
welcome() {
|
|
95
|
-
console.log(this.messages.general.welcome);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
async start() {
|
|
99
|
-
await this.init();
|
|
100
|
-
this.welcome();
|
|
101
|
-
await this.selectLanguage();
|
|
102
|
-
await this.selectPlatform();
|
|
103
|
-
await this.selectInputMethod();
|
|
104
|
-
await this.selectPlantType();
|
|
105
|
-
await this.setPlantName();
|
|
106
|
-
await this.generatePlantInfo();
|
|
107
|
-
await this.setupSensors();
|
|
108
|
-
this.setupAlerts();
|
|
109
|
-
this.activateAlerts();
|
|
110
|
-
this.startMonitoring();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async selectLanguage() {
|
|
114
|
-
const response = await prompt({
|
|
115
|
-
type: 'select',
|
|
116
|
-
name: 'language',
|
|
117
|
-
message: 'Select language:',
|
|
118
|
-
choices: [
|
|
119
|
-
{ name: 'en', message: 'English' },
|
|
120
|
-
{ name: 'es', message: 'Español' },
|
|
121
|
-
{ name: 'fr', message: 'Français' },
|
|
122
|
-
{ name: 'de', message: 'Deutsch' },
|
|
123
|
-
{ name: 'it', message: 'Italiano' },
|
|
124
|
-
{ name: 'pt', message: 'Português' },
|
|
125
|
-
{ name: 'nl', message: 'Nederlands' },
|
|
126
|
-
{ name: 'ru', message: 'Русский' },
|
|
127
|
-
{ name: 'zh', message: '中文' },
|
|
128
|
-
{ name: 'ja', message: '日本語' }
|
|
129
|
-
]
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
await this.setLanguage(response.language);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async selectPlatform() {
|
|
136
|
-
const response = await prompt({
|
|
137
|
-
type: 'select',
|
|
138
|
-
name: 'platform',
|
|
139
|
-
message: this.messages.general.selectPlatform,
|
|
140
|
-
choices: [
|
|
141
|
-
{ name: 'raspberry', message: 'Raspberry Pi' },
|
|
142
|
-
{ name: 'arduino', message: 'Arduino' }
|
|
143
|
-
]
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
this.platform = response.platform;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async selectInputMethod() {
|
|
150
|
-
const response = await prompt({
|
|
151
|
-
type: 'select',
|
|
152
|
-
name: 'method',
|
|
153
|
-
message: this.messages.general.selectInputMethod,
|
|
154
|
-
choices: [
|
|
155
|
-
{ name: 'local', message: this.messages.general.local },
|
|
156
|
-
{ name: 'extern', message: this.messages.general.external }
|
|
157
|
-
]
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
if (response.method === 'local') {
|
|
161
|
-
console.log(this.messages.general.localSelected);
|
|
162
|
-
const aiDetector = new AIDetector();
|
|
163
|
-
const aiModels = await aiDetector.detectAI();
|
|
164
|
-
if (aiModels) {
|
|
165
|
-
const modelResponse = await prompt({
|
|
166
|
-
type: 'select',
|
|
167
|
-
name: 'model',
|
|
168
|
-
message: this.messages.general.selectAIModel,
|
|
169
|
-
choices: aiModels.models
|
|
170
|
-
});
|
|
171
|
-
console.log(this.messages.general.selectedAIModel.replace('{model}', modelResponse.model));
|
|
172
|
-
} else {
|
|
173
|
-
console.log(this.messages.general.noLocalAI);
|
|
174
|
-
}
|
|
175
|
-
} else if (response.method === 'extern') {
|
|
176
|
-
console.log(this.messages.general.externSelected);
|
|
177
|
-
const apiKeyResponse = await prompt({
|
|
178
|
-
type: 'password',
|
|
179
|
-
name: 'apiKey',
|
|
180
|
-
message: this.messages.general.enterAPIKey
|
|
181
|
-
});
|
|
182
|
-
this.apiKey = apiKeyResponse.apiKey;
|
|
183
|
-
} else {
|
|
184
|
-
console.log(this.messages.general.invalidMethod);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
async selectPlantType() {
|
|
189
|
-
const response = await prompt({
|
|
190
|
-
type: 'select',
|
|
191
|
-
name: 'type',
|
|
192
|
-
message: this.messages.general.selectPlantType,
|
|
193
|
-
choices: [
|
|
194
|
-
{ name: 'indoor', message: this.messages.general.indoor },
|
|
195
|
-
{ name: 'outdoor', message: this.messages.general.outdoor }
|
|
196
|
-
]
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
if (['indoor', 'outdoor'].includes(response.type)) {
|
|
200
|
-
this.plantType = response.type;
|
|
201
|
-
} else {
|
|
202
|
-
console.log(this.messages.general.invalidType);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
async setPlantName() {
|
|
207
|
-
const response = await prompt({
|
|
208
|
-
type: 'input',
|
|
209
|
-
name: 'name',
|
|
210
|
-
message: this.messages.general.enterPlantName
|
|
211
|
-
});
|
|
212
|
-
this.plantName = response.name;
|
|
213
|
-
console.log(this.messages.general.plantNameSet.replace('{name}', this.plantName));
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
async generatePlantInfo() {
|
|
217
|
-
console.log(this.messages.general.generatingPlantInfo);
|
|
218
|
-
try {
|
|
219
|
-
this.plantInfo = await this.plantInfoGenerator.generatePlantInfo(this.plantName, this.plantType);
|
|
220
|
-
console.log(this.formatPlantInfo(this.plantInfo));
|
|
221
|
-
} catch (error) {
|
|
222
|
-
console.error(`Error generating plant info: ${error.message}`);
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
formatPlantInfo(data) {
|
|
227
|
-
return `
|
|
228
|
-
📋 Description: ${data.description}
|
|
229
|
-
🔍 Characteristics: ${data.characteristics}
|
|
230
|
-
💧 Moisture level: Ideal ${data.moisture.ideal}%, Range ${data.moisture.min}%-${data.moisture.max}%
|
|
231
|
-
🌞 Light level: Ideal ${data.light.ideal} lux, Range ${data.light.min}-${data.light.max} lux
|
|
232
|
-
🌡️ Temperature range: Ideal ${data.temperature.ideal}°C, Range ${data.temperature.min}-${data.temperature.max}°C
|
|
233
|
-
`;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
async setupSensors() {
|
|
237
|
-
console.log(this.messages.general.settingUpSensors);
|
|
238
|
-
// Initialize sensors based on plant info
|
|
239
|
-
this.sensors.moisture = this.plantInfo.moisture.ideal + (Math.random() - 0.5) * 10;
|
|
240
|
-
this.sensors.light = this.plantInfo.light.ideal + (Math.random() - 0.5) * 100;
|
|
241
|
-
this.sensors.temperature = this.plantInfo.temperature.ideal + (Math.random() - 0.5) * 2;
|
|
242
|
-
console.log(this.messages.general.sensorsReady);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
setupAlerts() {
|
|
246
|
-
this.alerts = {
|
|
247
|
-
moisture: { min: this.plantInfo.moisture.min, max: this.plantInfo.moisture.max },
|
|
248
|
-
light: { min: this.plantInfo.light.min, max: this.plantInfo.light.max },
|
|
249
|
-
temperature: { min: this.plantInfo.temperature.min, max: this.plantInfo.temperature.max }
|
|
250
|
-
};
|
|
251
|
-
console.log(this.messages.general.alertsConfigured);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
activateAlerts() {
|
|
255
|
-
console.log(this.messages.general.alertsActivated);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
startMonitoring() {
|
|
259
|
-
console.log(this.messages.general.startingMonitoring);
|
|
260
|
-
setInterval(() => this.checkPlantStatus(), 5000); // Check every 5 seconds
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
checkPlantStatus() {
|
|
264
|
-
console.log(this.messages.general.checkingStatus);
|
|
265
|
-
this.updateSensorData();
|
|
266
|
-
this.checkAlerts();
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
updateSensorData() {
|
|
270
|
-
// Simulate sensor data changes
|
|
271
|
-
this.sensors.moisture += (Math.random() - 0.5) * 5;
|
|
272
|
-
this.sensors.light += (Math.random() - 0.5) * 50;
|
|
273
|
-
this.sensors.temperature += (Math.random() - 0.5) * 2;
|
|
274
|
-
|
|
275
|
-
// Ensure values stay within realistic ranges
|
|
276
|
-
this.sensors.moisture = Math.max(0, Math.min(100, this.sensors.moisture));
|
|
277
|
-
this.sensors.light = Math.max(0, Math.min(1000, this.sensors.light));
|
|
278
|
-
this.sensors.temperature = Math.max(0, Math.min(50, this.sensors.temperature));
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
checkAlerts() {
|
|
282
|
-
for (const [sensor, value] of Object.entries(this.sensors)) {
|
|
283
|
-
if (value < this.alerts[sensor].min) {
|
|
284
|
-
console.log(this.messages.alerts[sensor].low.replace('{value}', value.toFixed(2)));
|
|
285
|
-
} else if (value > this.alerts[sensor].max) {
|
|
286
|
-
console.log(this.messages.alerts[sensor].high.replace('{value}', value.toFixed(2)));
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
class AIDetector {
|
|
293
|
-
async detectAI() {
|
|
294
|
-
try {
|
|
295
|
-
const output = execSync('ollama list', { encoding: 'utf-8' });
|
|
296
|
-
const models = output.split('\n').filter(line => line.trim()).map(line => line.split(' ')[0]);
|
|
297
|
-
if (models.length > 0) {
|
|
298
|
-
return {
|
|
299
|
-
name: 'ollama',
|
|
300
|
-
models: models
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
} catch (error) {
|
|
304
|
-
console.error('Error detecting AI:', error.message);
|
|
305
|
-
}
|
|
306
|
-
return null;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Initialize SmartPlant
|
|
311
|
-
const smartPlant = new SmartPlant();
|
|
312
|
-
smartPlant.start();
|
|
313
|
-
|
|
314
|
-
export default SmartPlant
|