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.
Files changed (4) hide show
  1. package/README.md +2 -1
  2. package/comingsoon.js +6 -0
  3. package/package.json +109 -111
  4. package/index.js +0 -314
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
- SmartPlant README
2
1
 
3
2
  # SmartPlant
4
3
 
4
+ ![banner](docs/banner.png)
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
@@ -0,0 +1,6 @@
1
+ console.log(`COMING SOON!!
2
+ View development progress at https://github.com/pigeonposse/smartplant
3
+
4
+ Funding: https://github.com/sponsors/pigeonposse
5
+ Repo: https://github.com/pigeonposse/smartplant
6
+ `)
package/package.json CHANGED
@@ -1,116 +1,114 @@
1
1
  {
2
- "name": "smartplant",
3
- "version": "0.1.0",
4
- "description": "A library for managing plant care with alerts and multi-language support.",
5
- "main": "index.js",
6
- "type": "module",
7
-
8
- "dependencies": {
9
- "@serialport/parser-readline": "^12.0.0",
10
- "axios": "^1.7.7",
11
- "chalk": "^5.3.0",
12
- "enquirer": "^2.4.1",
13
- "nodemailer": "^6.9.15",
14
- "readline": "^1.3.0",
15
- "serialport": "^12.0.0"
16
- },
17
- "keywords": [
18
- "plant",
19
- "care",
20
- "alerts",
21
- "multi-language",
22
- "smart",
23
- "AI",
24
- "intelligence",
25
- "npm",
26
- "library"
27
- ],
28
- "author": "Alejo Malia <alejomalia@gmail.com>",
29
- "files": [
30
- "./README.md"
31
- ],
32
- "packageManager": "pnpm@9.7.0",
33
- "publishConfig": {
34
- "access": "public",
35
- "registry": "https://registry.npmjs.org/"
36
- },
37
- "homepage": "https://github.com/pigeonposse/personality",
38
- "repository": {
39
- "type": "git",
40
- "url": "https://github.com/pigeonposse/personality"
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
- "bugs": {
47
- "url": "https://github.com/pigeonposse/personality/issues",
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